как отправить на основную очередь синхронно без тупика?

<p>мне нужно отправить блок в главной очереди синхронно. я не знаю, работаю ли я в основном потоке или нет. наивное решение выглядит так:</p><pre><code>dispatch\_sync(dispatch\_get\_main\_queue(), block); </code></pre><p>но если я в данный момент нахожусь в блоке, работающем в главной очереди, этот вызов создает тупик. (синхронная отправка ожидает окончания блока, но блок даже не запускается, так как мы ожидаем завершения текущей.)</p><p>очевидным следующим шагом является проверка текущей очереди:</p><pre><code>if (dispatch\_get\_current\_queue() == dispatch\_get\_main\_queue()) { block(); } else { dispatch\_sync(dispatch\_get\_main\_queue(), block); } </code></pre><p>это работает, но это ужасно. прежде чем я хотя бы спрятал ее за какой-нибудь пользовательской функцией, разве нет лучшего решения этой проблемы? я подчеркиваю, что я не могу позволить асинхронную диспетчеризацию блока - приложение находится в ситуации, когда асинхронно отправленный блок будет выполнен "слишком поздно".</p>

<p>мне нужно довольно часто использовать что-то подобное в моих приложениях mac и ios, поэтому я использую следующую вспомогательную функцию (первоначально описанную в <a href="https://stackoverflow.com/a/5226271/19679">этот ответ</a> ):</p><pre><code>void runonmainqueuewithoutdeadlocking(void (^block)(void)) { if ([nsthread ismainthread]) { block(); } else { dispatch\_sync(dispatch\_get\_main\_queue(), block); } } </code></pre><p>через который вы звоните</p><pre><code>runonmainqueuewithoutdeadlocking(^{ //do stuff }); </code></pre><p>это в значительной степени процесс, который вы описали выше, и я поговорил с несколькими другими разработчиками, которые самостоятельно создали что-то подобное для себя.</p><p>я использовал <code>[nsthread ismainthread]</code> вместо проверки <code>dispatch\_get\_current\_queue()</code>, потому что <a href="http://developer.apple.com/library/mac/#documentation/darwin/reference/manpages/man3/dispatch\_get\_current\_queue.3.html">раздел caveats для этой функции</a> однажды предупреждал против использования этого для проверки идентичности и <a href="https://stackoverflow.com/questions/13237417/alternatives-to-dispatch-get-current-queue-for-completion-blocks-in-ios-6">вызов был исключен в ios 6</a> .</p>

<p>для синхронизации в основной очереди или в основном потоке (это не одно и то же) я использую:</p><pre><code>import foundation private let mainqueuekey = unsafemutablepointer<void>.alloc(1) private let mainqueuevalue = unsafemutablepointer<void>.alloc(1) public func dispatch\_sync\_on\_main\_queue(block: () -> void) { struct dispatchonce { static var token : dispatch\_once\_t = 0 } dispatch\_once(&dispatchonce.token, { dispatch\_queue\_set\_specific(dispatch\_get\_main\_queue(), mainqueuekey, mainqueuevalue, nil) }) if dispatch\_get\_specific(mainqueuekey) == mainqueuevalue { block() } else { dispatch\_sync(dispatch\_get\_main\_queue(),block) } } extension nsthread { public class func runblockonmainthread(block: () -> void ) { if nsthread.ismainthread() { block() } else { dispatch\_sync(dispatch\_get\_main\_queue(),block) } } public class func runblockonmainqueue(block: () -> void) { dispatch\_sync\_on\_main\_queue(block) } } </code></pre>

<p>недавно я начал испытывать тупик во время обновления пользовательского интерфейса. это привело меня к вопросу о переполнении стека, в результате чего я реализовал вспомогательную функцию типа <code>runonmainqueuewithoutdeadlocking</code> на основе принятого ответа.</p><p>однако реальная проблема заключается в том, что при обновлении пользовательского интерфейса из блока я по ошибке использовал <code>dispatch\_sync</code> вместо <code>dispatch\_async</code> для получения главной очереди для обновлений пользовательского интерфейса. легко сделать с завершением кода, и, возможно, трудно заметить после факта.</p><p>таким образом, для других читающих этот вопрос: <strong>если синхронное выполнение не требуется</strong>, простое использование <code>dispatch\_**a**sync</code> поможет избежать тупика, в который вы можете периодически попадать.</p>