Подтвердить что ты не робот

IOS Являются ли методы, вызванные делегатами и наблюдателями, выполняемыми в основном потоке?

Извините, я не уверен в правильном языке здесь, но когда методы вызываются, потому что они являются либо методами делегата, либо методами, называемыми в результате того, что они указаны как цель наблюдателя, выполняются ли они на основном нить?

Мне интересно, могу ли я просто внести изменения в пользовательские интерфейсы в этих методах или мне нужно их обернуть в

    dispatch_async(dispatch_get_main_queue(), ^{ UI stuff });

TIA: John

4b9b3361

Ответ 1

Для делегатов это может различаться. Если документация не указана, то обычно они отправляются в основной поток. Традиционно UIKit должен использоваться в основном потоке, чтобы эти делегаты почти всегда вызывались из основного потока.

Для уведомлений я думаю, что вам нужен этот маленький снип.

Центр уведомлений синхронно передает уведомления наблюдателям. Другими словами, методы postNotification: не возвращаются до тех пор, пока все наблюдатели не получат и не обработают уведомление. Для отправки уведомлений асинхронно используйте NSNotificationQueue. В многопоточном приложении уведомления всегда доставляются в потоке, в котором было отправлено уведомление, которое может не быть тем же самым потоком, в котором наблюдатель зарегистрировал себя.

От http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsnotificationcenter_Class/Reference/Reference.html

И, наконец, для KVO уведомления могут поступать из других потоков. Вот что сказал Apple Engineer о том, как обращаться с ними.

http://lists.apple.com/archives/cocoa-dev/2007/May/msg00022.html

Ответ 2

Как указано, поток будет меняться в зависимости от вызывающего. В методе делегата, если вам нужно адаптироваться, вы всегда можете сделать что-то вроде этого:

if ([NSThread isMainThread]) {
    // do the UI stuff as normal
} else {
    dispatch_async(dispatch_get_main_queue(), ^{ UI stuff });
}

Ответ 3

Основная идея заключается в том, что во всех случаях метод наблюдателя или делегата вызывается в том же потоке, что и начальное уведомление (для шаблона наблюдателя) или делегирующий код, поэтому, если вы не уверены, что он рекомендует отправлять ваш интерфейс блок в основном потоке. Я попытаюсь оправдать эти утверждения в рассуждениях ниже, конечно, я могу ошибаться.

Если явно не указано в документации протокола делегата, в шаблоне делегата метод вызывается непосредственно в том же потоке, вызывающий работает в момент вызова. Например. если вызывающий (делегирующий объект) хочет вызвать своего делегата и в настоящее время работает в "Thread-1", тогда вызов будет происходить в том же потоке:


// this is running in "Thread-1" --> then aDelegateMethod will continue on "Thread-1"
[myDelegate aDelegateMethod]

Что касается шаблона наблюдателя, я не вижу никакой веской причины, по которой система должна отправлять уведомление о наблюдении явно в основном потоке, особенно если исходное изменение значения, которое отправляет уведомление, выполняется в другом потоке. Фактически в случае KVO среда выполнения изменяет определение класса, добавляя некоторые частные методы, которые переопределяют методы setter для выполнения уведомлений, и я не вижу действительной причины для этого вызова явно в основном потоке. Поэтому, по моему мнению, уведомление KVO может происходить из любого потока, и этот поток тот же, который запускает изменение значения в наблюдаемом классе.

Наконец, механизм, основанный на NSNotificationCenter, видит свои уведомления, вызываемые тем же потоком, где было отправлено исходное уведомление. Это четко указано в документации Apple (и стоит сказать, что каждый поток имеет свою собственную очередь уведомлений).

Таким образом, во всех случаях поток поддерживается, и если вы хотите убедиться, что ваш блок пользовательского интерфейса вызывается в основной очереди, используйте вызов GCD, который вы отправили в своем вопросе.