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

Почему установка объекта, который подвергается освобождению от слабых свойств, приводит к сбою

В 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;
}
4b9b3361

Ответ 1

Это не ошибка: она явно очень преднамеренная. Это отклонение от спецификации, но оно преднамеренное.

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

Они также могут подумать, что если вы все равно пытаетесь ослабить self, а вы не проверяете на nil weakref (довольно часто - много блочного кода повторно вызывает через weakref, что может пойти nil в любое время!), вы настраиваете себя на трудные отладки ошибок.

Все, что сказал, я хотел бы увидеть заметки за этим изменением времени исполнения.