2016-03-15 3 views
1

В рамках ResearchKit, я видел такой код:Цель проведения сильной локальной копии переменного делегат

- (void)finishWithReason:(ORKTaskViewControllerFinishReason)reason error:(NSError *)error { 
    __strong typeof(self.delegate) strongDelegate = self.delegate; 
    if ([strongDelegate respondsToSelector:@selector(taskViewController:didFinishWithReason:error:)]) { 
     [strongDelegate taskViewController:self didFinishWithReason:reason error:error]; 
    } 
} 

Что цель хранения местной сильной переменной указывая на делегат перед вызовом его метод? Разве это не позволяет делегату освободиться от другого потока между проверкой respondsToSelector: и вызовом метода? Может ли это вообще произойти?

Если это так, то почему вы хотите вызвать метод делегата? Почему бы не освободить его и выполнить no-op, который отправляет сообщение переменной nil?

+0

Я думаю, что если делегат освободится перед вызовом responsesToSelector, вызов responsesToSelector вызовет исключение (EXC_BAD_ACCESS?). Поскольку этот метод применим только к NSObject. Но если это так, я думаю, что перед вызовом метода responsesToSelector необходимо выполнить проверку сильногоDelegate! = Nil. – Surely

+0

Хотелось бы узнать об этом иначе, но я думаю, что это полная чушь. .delegate либо уже освобожден, либо нет, и ни один, ни другой, когда этот метод работает. Он не может быть освобожден во время выполнения этого метода. И никакое заклинание в начале, копируя указатель на переменную стека (которая по умолчанию по-прежнему сильно), изменяет эти условия. – danh

+0

@zp_x: Я боюсь, что вы ошибаетесь, слабые переменные заполняются, когда они освобождаются, а отправка сообщений в переменные nil просто не работает. –

ответ

1

Существуют предупреждения Clang, которые отправляют сообщения флагов слабым (возможно, ноль) указателям и неоднократно обращаются к слабым (возможно, ноль) указателям. Это побуждает разработчика рассуждать о том, «что, если этот указатель равен, когда я получаю доступ к нему?» и «что, если эта слабая ссылка идет nil после Я тестирую не ноль?» и требует временного сильного хранения в области вызова для удовлетворения компилятора.

Что касается вашего конкретного вопроса о том, можно ли освободить делегата (или другого объекта с низкой ссылочной информацией) от другого потока между тестированием условия «если» и следующей строкой кода, ответ «да», как указано в описании, сопровождающее предупреждение добавляется в LLVM здесь:

http://reviews.llvm.org/rL164854

Что касается вопроса о том, почему не позволить делегату быть освобожден и просто сообщение не будет не цитом до нулевого указателя: компилятор нет способа понять, является ли это поведение безопасным или предназначенным, и поэтому требуется разработчик (если у вас есть эти предупреждения включены), чтобы использовать сильную ссылку на t он получает объект как гарантию того, что сообщение будет успешным, поскольку в этом подразумевается, что он предполагает.

Более подробное обсуждение по этому вопросу в WWDC 2013 "Прогресс в Objective-C" сессии здесь:

https://developer.apple.com/videos/play/wwdc2013/404/ (около 47:30)

И в списке рассылки нить здесь:

http://lists.apple.com/archives/objc-language/2012/Aug/msg00001.html

Смежные вопросы