2017-02-19 12 views
0

Скажите, что карта NSDictioanry, я понимаю, так как адрес res не изменяется в блоке, нам не нужно использовать __block для него. Это верно?Нужно ли использовать спецификатор типа __block для изменяемых в блоках изменяемых объектов?

//__block NSMutableArray *res = [@[] mutableCopy]; 
NSMutableArray *res = [@[] mutableCopy]; 
__block NSInteger i = 0; 
[map enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSArray *v, BOOL *stop) { 
    [res addObject:v]; 
    i++; 
}]; 

Кстати, я запустил код, он отлично работает.

+0

Прокомментировал ли компилятор? Запустите код и напечатайте 'res'. Что происходит? – vadian

+0

Я запустил его, он отлично работает – user3315620

+0

Тогда ответ: No :-) Компилятор скажет вам, отсутствует ли '__block'. – vadian

ответ

2

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

Поскольку блок не может быть вызван только в рамках метода, который его создает (это называется экранирование), ему может потребоваться изменить переменные, которые он ссылается после их удаления. Ссылки на вещи, которые идут в стеке (например, i в вашем примере), могут стать оборванными указателями, если блок удерживается в конце исходного метода или функции, поэтому, если они должны быть мутированы, их нужно хранить где-то еще чем стек. Спецификатор __block сообщает компилятору помещать переменную в отдельную память, которая будет действительна всякий раз, когда вызывается этот блок.

Для вещей, выделенных кучей (например, res), это необязательно - поскольку указатель на объект не будет изменяться, пока объект находится вокруг (каким он должен быть, поскольку блок сохранит его default), локальное хранилище указателя объекта не нужно помещать в альтернативное хранилище и может оставаться в стеке.

Если вы хотите узнать больше об этом, на странице документации Blocks and Variables есть подробная информация об управлении памятью с блоками и многое другое на типе хранения __block.

0

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

Здесь переменная i присваиваются внутри блока, с оператором ++, поэтому __block необходимо. Переменная res никогда не назначается нигде; переменная res равна , начиная с (не назначается) внутри блока.