Почему установка объекта, который подвергается освобождению от слабых свойств, приводит к сбою
В Clang Objective-C Автоматический подсчет ссылок мы видим следующее
Для объектов __weak значение lvalue обновляется, чтобы указать на нового pointee, если новый pointee не является объектом, который в настоящее время проходит освобождение, и в этом случае lvalue обновляется до нулевого указателя. Это должно выполняться атомарно по отношению к другим назначениям объекту, чтению с объекта и окончательному выпуску нового указателя.
В objc-weak.mm мы видим следующий фрагмент кода в weak_register_no_lock()
:
if (deallocating) {
if (crashIfDeallocating) {
_objc_fatal("Cannot form weak reference to instance (%p) of "
"class %s. It is possible that this object was "
"over-released, or is in the process of deallocation.",
(void*)referent, object_getClassName((id)referent));
} else {
return nil;
}
}
Я установил точку останова в моем подклассе UIViewController dealloc
и попытался вызвать [self allowsWeakReference]
в lldb, что привело к значению NO
.
Если мы попытаемся задать себе слабое свойство другого объекта, приложение будет разбиваться в соответствии с кодом objc-weak.mm.
Вопрос: почему это происходит? Является ли спецификация clang неправильной? Является ли это ошибкой в реализации objc?
Вот простой фрагмент кода, который воспроизведет сбой:
//cc -fmodules -fobjc-arc -g crash.m -o crash
@import Foundation;
@interface Foo : NSObject
@end
@implementation Foo
- (void)dealloc {
Foo * __weak weakSelf = self; // crashes on this line
}
@end
int main() {
(void)[[Foo alloc] init];
return 0;
}
Ответы
Ответ 1
Это не ошибка: она явно очень преднамеренная. Это отклонение от спецификации, но оно преднамеренное.
Основываясь на предупреждении, похоже, что они хотели упростить диагностику сценариев избыточного выпуска, а захват объектов, которые были освобождены в то время, может быть просто побочным эффектом этой основной цели.
Они также могут подумать, что если вы все равно пытаетесь ослабить self
, а вы не проверяете на nil
weakref (довольно часто - много блочного кода повторно вызывает через weakref, что может пойти nil
в любое время!), вы настраиваете себя на трудные отладки ошибок.
Все, что сказал, я хотел бы увидеть заметки за этим изменением времени исполнения.