ARC - Значение __unsafe_unretained?

Просто хочу убедиться, что я правильно понял:

  1. Нужно ли мне __unsafe_unretain объекты, которыми я не владею?
  2. Если объект __unsafe_unretained, нужно ли использовать assign в @property? Означает ли это, что объект не сохраняется, а просто ссылается на объект, которому я назначаю?
  3. Когда бы я хотел использовать его, кроме делегатов?
  4. Это что-то из ARC или раньше использовалось?

person shannoga    schedule 21.12.2011    source источник


Ответы (4)


Компилятор LLVM 3.0 представляет четыре новых квалификатора владения: __strong, __autoreleasing, __unsafe_unretained и __weak. Первые три доступны даже за пределами ARC, согласно спецификации.

Как указывает Джошуа, по умолчанию все указатели считаются __strong под ARC. Это означает, что когда объект назначается этому указателю, он сохраняется до тех пор, пока этот указатель ссылается на него. Это хорошо для большинства вещей, но открывает возможность для циклов сохранения, как я описал в своем ответе здесь. Например, если у вас есть объект, который содержит другой объект в качестве переменной экземпляра, но этот второй объект имеет сильную обратную связь с первым в качестве своего делегата, два объекта никогда не будут освобождены.

Именно по этой причине существуют квалификаторы __unsafe_unretained и __weak. Чаще всего они используются для делегатов, где вы определяете свойство для этого делегата с помощью атрибута weak или unsafe_unretained (assign фактически равно unsafe_unretained), а затем сопоставляете его, помечая соответствующую переменную экземпляра с помощью __weak или __unsafe_unretained. Это означает, что переменная экземпляра делегата по-прежнему будет указывать на первый объект, но это не приведет к сохранению этого объекта, что нарушит цикл сохранения и позволит освободить оба объекта.

Помимо делегатов, это полезно для прерывания любых других циклов сохранения, которые могут образоваться в вашем коде. Полезно то, что инструмент Leaks теперь включает в себя представление Cycles, которое графически показывает циклы сохранения, которые он обнаруживает в вашем приложении.

И __unsafe_unretained, и __weak предотвращают сохранение объектов, но немного по-разному. Для __weak указатель на объект преобразуется в nil при освобождении объекта, на который он указывает, что является очень безопасным поведением. Как следует из названия, __unsafe_unretained будет по-прежнему указывать на память, в которой находился объект, даже после того, как он был освобожден. Это может привести к сбоям из-за доступа к этому освобожденному объекту.

Зачем тогда тебе использовать __unsafe_unretained? К сожалению, __weak поддерживается только для iOS 5.0 и Lion в качестве целей развертывания. Если вы хотите вернуться к iOS 4.0 и Snow Leopard, вам нужно использовать квалификатор __unsafe_unretained или что-то вроде MAZeroingWeakRef.

person Brad Larson    schedule 21.12.2011
comment
И, конечно же, __unsafe_unretained может быть полезен для определения массивов C NSString констант и т.п., например. NSString __unsafe_unretained *myStrings = { @"Foo", @"Bar", @"Baz", nil }; - person jlehr; 21.12.2011
comment
Спасибо за отличный ответ. когда я использую __unsafe_unretained, будет ли iOS называть его _weak, если ОС устройства равна 5? или он устанавливается во время компиляции на xCode? - person shannoga; 21.12.2011
comment
@shannoga - Нет, вам нужно вручную указать __weak в качестве квалификатора, чтобы использовать такие указатели. Вы по-прежнему можете использовать __unsafe_unretained только с целью 5.0, и она не будет вести себя как __weak. Если вам нужно что-то, что будет переключаться между двумя режимами в зависимости от того, поддерживает ли его ваша цель, вы можете использовать специфичное для компилятора определение, как я предлагаю здесь: stackoverflow.com/a/8594878/19679 - person Brad Larson; 21.12.2011
comment
@jlehr - NSString *myStrings = { @"Foo", @"Bar" }; недопустимый синтаксис Objective-C; @"Foo" имеет тип NSString* сам по себе. Возможно, вы имели в виду NSString *myStrings[] = { @"Foo", @"Bar" };, но в таком случае я не совсем понимаю, чем __unsafe_unretained может быть особенно полезен. - person Quuxplusone; 11.07.2012
comment
@Quuxplusone Правильно по обоим пунктам - я смешивал массивы C со структурами. Я должен был сказать, что __unsafe_unretained может быть полезным членом C-структуры, указывающим на константы NSString, например. struct foo { __unsafe_unretained NSString * const s; int x; }; - person jlehr; 11.07.2012
comment
@BradLarson также обнаружил замену '__unsafe_unretained' в __unsafe_unretained __block void (^assignPropertyValues)(NSDictionary*, NSManagedObject*); с «__weak», как я называю, блок внутри блока приводит к предупреждению: присваивание литерала блока слабой переменной; объект будет освобожден после назначения - person Rambatino; 02.12.2014
comment
Также имеет значение для Class. См.: stackoverflow.com/a/14245894/392847 - person Quintin Willison; 04.05.2017

  1. Нет, вы также можете использовать weak для объектов, которыми вы не владеете.
  2. Нет, вы также можете использовать unsafe_unretained для собственности.
  3. Я так понимаю, что unsafe_unretained элементы такие же, как weak, без дополнительной безопасности их очистки, когда элемент, на который они указывают, освобождается (и связанные с этим накладные расходы).
  4. Это полностью ARC вещь.
person Sergey Kalinichenko    schedule 21.12.2011
comment
На самом деле, как ни странно, unsafe_unretained iVars, установленные во время выполнения, ведут себя точно так же, как strong, что наводит меня на мысль, что unsafe_unretained — это просто подсказка компилятора, а weak — нет. Дополнительная информация здесь: stackoverflow.com/questions/11621028/ - person Richard J. Ross III; 24.07.2012

__unsafe_unretained идентично тому, каким было хранилище объекта по умолчанию до ARC. С ARC по умолчанию теперь __strong, что означает, что у вас есть ссылка на него, пока ваша ссылка не выйдет за рамки.

person Joshua Weinberg    schedule 21.12.2011

Еще одно наблюдение по поводу __unsafe_unretained: у меня были сбои в моем приложении на устройстве и НЕ на симуляторе с iVars, объявленными как __unsafe_unretained! Да, это была ошибка в коде от миграции ARC, но я впервые заметил такую ​​разницу между устройством и симулятором.

person Gerd    schedule 19.11.2012