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

Определение Objective-C блоков как свойств - наилучшая практика

Недавно я встретил документ Apple, в котором показано следующее объявление свойства для блока:

@interface XYZObject : NSObject
@property (copy) void (^blockProperty)(void);
@end

Кроме того, в этой статье говорится:

Примечание. Вы должны указать копию как атрибут свойства, поскольку блок необходимо скопировать, чтобы отслеживать захваченное состояние вне исходной области. Это не то, о чем вам нужно беспокоиться при использовании автоматического подсчета ссылок, поскольку это произойдет автоматически, но его лучшая практика для атрибута свойства показать результирующее поведение. Дополнительные сведения см. В разделе "Темы программирования блоков".

Я также читал предлагаемые разделы программирования блоков, но не нашел там ничего подходящего.

Мне все еще интересно узнать, почему определение свойства блока как "копия" - лучшая практика. Если у вас есть хороший ответ, попробуйте различать различия между ARC и MRC, если они есть.

Спасибо

4b9b3361

Ответ 1

По умолчанию блоки создаются в стеке. Это означает, что они существуют только в том объеме, в котором они были созданы.

Если вы хотите получить к ним доступ позже, их нужно скопировать в кучу, отправив сообщение copy блочному объекту. ARC сделает это для вас, как только обнаружится, что к блоку нужно получить доступ за пределами области его создания. В качестве наилучшей практики вы объявляете какое-либо свойство блока как копию, потому что так должно быть в автоматическом управлении памятью.

Прочитайте Объекты стека и кучи в Objective-C Майка Эша для получения дополнительной информации о стеке и куче.

Ответ 2

Блоки по умолчанию выделяются в стеке. Это оптимизация, поскольку распределение стека намного дешевле, чем распределение кучи. Выделение стека означает, что по умолчанию снова перестанет существовать блок, когда область, в которой она объявлена, выйдет. Таким образом, свойство блока с семантикой retain приведет к оборванному указателю на блок, который больше не существует.

Чтобы переместить блок из стека в кучу (и, таким образом, дать ему нормальную семантику управления памятью Objective-C и расширенное время жизни), вы должны скопировать блок через [theBlock copy], Block_copy(theBlock) и т.д. куча, время жизни блока может управляться по мере необходимости, сохраняя/освобождая его. (Да, это также относится к ARC, вам просто не нужно вызывать -retain/-release самостоятельно.)

Итак, вы хотите объявить свойства блока с помощью семантики copy, чтобы блок копировался при установке свойства, избегая оборванного указателя на блок на основе стека.

Ответ 3

"Лучшие практики", на которые вы ссылаетесь, просто говорят: "Видя, как ARC собирается волшебным образом скопировать ваш блок, независимо от того, что вы здесь пишете, вам лучше всего написать" копию ", чтобы не путать будущие поколения, глядя на ваши код".

Пояснение следует:

Как правило, вам не нужно копировать (или сохранять) блок. Вам нужно только сделать копию, когда вы ожидаете, что блок будет использоваться после уничтожения области, в которой он был объявлен. Копирование перемещает блок в кучу.
-Blocks Темы программирования: использование блоков, копирование блоков

Ясно, что назначение блока для свойства означает, что он может использоваться после того, как область, в которой она была объявлена, была уничтожена. Таким образом, согласно темам программирования блоков, блок должен быть скопирован в кучу с помощью Block_copy.

Но ARC позаботится об этом для вас:

Блоки "просто работают", когда вы передаете блоки вверх в стек в режиме ARC, например, в возврате. Вам больше не нужно называть Block Copy.
- Переход к ARC

Обратите внимание, что это не о семантике retain блока. Просто нет возможности для существования блочного контекста, не будучи перемещенным из стека (в скором времени) и в кучу. Поэтому, независимо от того, какие атрибуты вы квалифицируете для своего @property, ARC все равно собирается скопировать блок.