Почему Block использует struct __Block_byref_object_0 вместо одного указателя для захвата переменной, украшенной "__block" - PullRequest
0 голосов
/ 19 декабря 2018

Вот мой исходный код в файле main.m

 __block NSInteger blockInteger = 123;
 static NSInteger staticInteger = 123;
 void (^testBlock)(void) = ^() {
     blockInteger++;
     staticInteger++;
     NSLog(@"%ld", blockInteger);
     NSLog(@"%ld", staticInteger);
 };
 testBlock();

Когда я использовал команду clang "clang -rewrite-objc main.m", я получил это

struct __Block_byref_blockInteger_0 {
   void *__isa;
   __Block_byref_blockInteger_0 *__forwarding;
   int __flags;
   int __size;
   NSInteger blockInteger;
};
struct __main_block_impl_0 {
   struct __block_impl impl;
   struct __main_block_desc_0* Desc;
   NSInteger *staticInteger;
   __Block_byref_blockInteger_0 *blockInteger; // by ref
   ...
};

Мне интересно, почему блок использует __Block_byref_blockInteger_0 для захвата blockInteger, поскольку он использует указатель NSInteger для захвата статической переменной.Что конкретно делает __Block_byref_blockInteger_0?Каковы преимущества этой структуры по сравнению с указателем?

1 Ответ

0 голосов
/ 19 декабря 2018

Компилятор создает ряд структур, чтобы помочь блоку ссылаться на его «вложенные» значения.(Помните, что блок создает копию или «охватывает» все значения, находящиеся вне блока, поэтому блоки также называют «замыканиями».)

Итак, первая структура (__Block_byref_blockInteger_0) создает объект для инкапсуляции blockInteger автоматически.Это связано с тем, что автоматические переменные исчезают в конце функции, но блоки должны иметь возможность ссылаться на них долгое время спустя.

Вторая структура инкапсулирует все значения (включая __Block_byref_blockInteger_0), которые "захвачены""блоком.Это дает блоку единственную ссылку на все его вложенные значения, скопированные при создании блока.

Теперь значение экземпляра NSInteger *staticInteger немного странная утка, так как адрес глобального staticInteger не может измениться.Но это довольно незначительная разница, так как это всего лишь копия адреса;может ли этот адрес измениться, не имеет значения.

Я подозреваю, что это из-за области имен;статика, объявленная внутри функции, имеет ограниченную область действия символа.И если вы посмотрите на вывод компилятора, вы увидите, что каждый объявленный вами блок создает невидимую статическую функцию, которая содержит его код.Поскольку эта вторая статическая функция обычно не может ссылаться на статический объект, объявленный в другой функции, создание копии адреса статического объекта - единственный способ для функции блока получить к ней доступ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...