Блокирует управление памятью

В этом справочнике Apple есть концептуальный обзор объектов Blocks в Objective-C:

http://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Blocks/Blocks.pdf

Однако на самом деле это не объясняет две темы, которые волнуют меня и могут волновать других людей. Первый вопрос таков: могу ли я присвоить nil ссылке Block? Или я должен использовать NULL? Или я могу использовать ни один из них?

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

-(void)makeTheClass
{
    TheClass *object = [[TheClass alloc] init];

    object.blockReference = ^(void) { return nil; } 
}

Этот объект, созданный в какой-то области видимости, будет уничтожен после того, как выйдет из нее. Но объект TheClass на самом деле будет хранить ссылку на этот (почти уничтоженный) блок:

typedef id (^WeirdBlockType)(void);

@interface TheClass {
    WeirdBlockType blockReference;   
}

Как объявить свойство класса для такого блока? В чем разница между этими двумя:

@property (nonatomic, retain) WeirdBlockType blockReference;
@property (nonatomic, copy)   WeirdBlockType blockReference; 

?

В документации Apple четко сказано, что блочное копирование перемещает блок в кучу. Но что, если я просто сохраню его? Будет ли он уничтожен после того, как выйдет из области действия метода makeTheClass?


person wh1t3cat1k    schedule 13.11.2010    source источник


Ответы (2)


Что ж, я нашел решение. Спасибо Годжану за его ответ, но на самом деле он ошибся в одном месте:

Вева был прав. Сохранение блока не действует до тех пор, пока он полностью не перемещен в кучу, и только Block_copy выполняет такую ​​задачу.

Возможно, блоки — не единственные объекты, которые нельзя сохранить, пока они находятся в стеке; но пока вы создаете (alloc и init) любые экземпляры подкласса NSObject в куче по умолчанию, вас это не волнует - retain работает как обычно. Блочные объекты создаются в стеке по умолчанию, поэтому работают немного неожиданно.

Спасибо всем!

person wh1t3cat1k    schedule 14.11.2010
comment
Я все еще пытаюсь понять это, но я думаю, что предложение Retain on a block [literal] не имеет никакого эффекта, не совсем верно: оно действительно увеличивает количество сохранений блока, верно? Однако он все еще будет в стеке, поэтому я думаю, что это действительно мало полезно, так как он все равно будет уничтожен, как только мы покинем фрейм стека. Вероятно, я ответил на свои сомнения здесь :) просто интересно, имеет ли это смысл. Спасибо, в любом случае. - person ettore; 24.08.2012

могу ли я присвоить nil ссылке на блок? Или я должен использовать NULL?

nil можно прочитать как «пустой тип id», а NULL определяется как ((void *)0). Разница здесь в контексте. Если вы работаете с объектами на основе NSObject, вы должны использовать nil.

В случае блоков вы должны использовать nil, потому что вы можете взаимодействовать с блоком, как если бы это был NSObject (вы можете сохранить его, освободить и т. д.). Но если вы используете NULL, это должно работать.

Как объявить свойство класса для такого блока? В чем разница между этими двумя:

@property (nonatomic, retain) WeirdBlockType blockReference;
@property (nonatomic, copy)   WeirdBlockType blockReference; 

?

В документации сказано:

Если вы используете Objective-C, вы можете отправлять блочные копии, сохранять и выпускать (и автоматически выпускать) сообщения.

Таким образом, оба объявления действительны, но если вы спросите меня, я предпочитаю retain, чем copy.

В заключении:

Блоки обрабатываются как объекты, определенные и созданные в одно и то же время (время выполнения), поэтому после того, как вы получите постоянную ссылку на него, вы можете считать эту ссылку такой же, как и любой другой объект.

person Bruno Berisso    schedule 13.11.2010
comment
Если вы хотите, чтобы блок сохранялся за пределами области, в которой он был объявлен, вы должны скопировать его. - person Wevah; 13.11.2010