Блоки и переменные Objective-C


Сегодня я начал использовать блоки Objective-C. Я написал следующий код:

NSArray *array = @[@25, @"abc", @7.2];

    void (^print)(NSUInteger index) = ^(NSUInteger index)
    {
        NSLog(@"%@", array[index]);
    };

    for (int n = 0; n < 3; n++)
        print(n);

Который работает правильно. Мне нужно было изменить переменную array после ее объявления, поэтому я попытался использовать следующий код:

NSArray *array;

    void (^print)(NSUInteger index) = ^(NSUInteger index)
    {
        NSLog(@"%@", array[index]);
    };

    array = @[@25, @"abc", @7.2];

    for (int n = 0; n < 3; n++)
        print(n);
{[4] однако}, это не сработает. Консоль просто печатает (null) три раза. Почему это не работает, в то время как это работало с моим первым фрагментом кода?

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

2 7

2 ответа:

Это потому, что блок захватывает переменные по значению и при создании блока (Если вы не используете __block).

То, что вы, вероятно, хотите:

NSArray *array = @[@25, @"abc", @7.2];

void (^print)(NSUInteger index) = ^(NSUInteger index)
{
    NSLog(@"%@", array[index]);
};

for (int n = 0; n < 3; n++)
    print(n);

Пример с __block:

__block NSArray *array;

void (^print)(NSUInteger index) = ^(NSUInteger index)
{
    NSLog(@"%@", array[index]);
};

array = @[@25, @"abc", @7.2];

for (int n = 0; n < 3; n++)
    print(n);

Обратите внимание, что это немного менее эффективно использовать __block, Если вам на самом деле не нужно изменять переменную внутри блока и отражать ее снаружи.

Блок захватывает указатель array при создании. Вы можете добавить модификатор __block, чтобы блок захватил указатель по ссылке, но это обычно дорого и не рекомендуется. Лучше иметь блок захвата, созданный после того, как данные готовы к использованию внутри блока.