Список синтаксиса декларации блока

277

Блочный синтаксис в Objective C (и, как я полагаю, C), как известно, неуместен. Передача блоков в качестве аргументов выглядит иначе, чем объявление блоков как ivars, что выглядит иначе, чем в typedefблоках.

Есть ли полный список синтаксиса объявления блока, который я мог бы держать под рукой для быстрого ознакомления?

Патрик Перини
источник
9
Что не так с «Объявление и создание блоков» в Руководстве по темам программирования блоков?
ОАО
простое объяснение использования свойств блока: stackoverflow.com/a/20760583/294884
Толстяк

Ответы:

696

Список синтаксисов объявления блоков

Во всем, пусть

  • return_typeбыть типом объекта / примитива / и т.д. Вы хотели бы вернуться (обычно void)
  • blockName быть именем переменной блока, который вы создаете
  • var_typeбыть типом объекта / примитива / и т.д. вы хотели бы передать в качестве аргумента (оставьте пустым, без параметров)
  • varName быть именем переменной данного параметра

И помните, что вы можете создать столько параметров, сколько захотите.

Блоки как переменные

Возможно, самый распространенный способ декларации.

return_type (^blockName)(var_type) = ^return_type (var_type varName)
{
    // ...
};

Блоки как свойства

Очень похоже на объявление блоков в качестве переменных, но немного отличающихся.

@property (copy) return_type (^blockName) (var_type);

Блоки как параметры

Обратите внимание, что это отличается от «Блоки как аргументы»; в этом случае вы объявляете метод, который хочет аргумент блока.

- (void)yourMethod:(return_type (^)(var_type))blockName;

Блоки как аргументы

Обратите внимание, что это отличается от «Блоки как параметры»; в этом случае вы вызываете метод, который хочет аргумент блока с анонимным блоком. Если вы уже объявили блочную переменную, достаточно передать имя переменной в качестве аргумента.

[someObject doSomethingWithBlock: ^return_type (var_type varName)
{
    //...
}];

Анонимный блок

Функционально это анонимный блок, однако синтаксис для назначения блоков переменным состоит в том, чтобы просто установить переменную равной анонимному блоку.

^return_type (var_type varName)
{
    //...
};

typedef блок

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

typedef return_type (^blockName)(var_type);

Чтобы потом использовать blockNameвместо стандартного синтаксиса объявления блока, просто подставьте.

Встроенный блок

Возможно, это менее полезное использование блоков, но, тем не менее, может иметь место. Встроенный блок - это анонимный блок, вызываемый сразу после создания экземпляра.

^return_type (var_type varName)
{
    //...
}(var);

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

{
   //...
}

Рекурсивные блоки

Это позволяет вам вызывать блок из себя, создавая цикл, который можно использовать во время обратных вызовов и вызовов GCD. Этот метод создания экземпляров не содержит циклов сохранения в ARC.

__block return_type (^blockName)(var_type) = [^return_type (var_type varName)
{
    if (returnCondition)
    {
        blockName = nil;
        return;
    }

    // ...
} copy];
blockName(varValue);

Возвращающиеся блоки

Метод может вернуть блок,

- (return_type(^)(var_type))methodName
{
    // ...
}

как может функция, если немного странно.

return_type (^FunctionName())(var_type)
{
    // ...
}

Дополнения

Если я что-то пропустил, пожалуйста, дайте мне знать в комментариях, и я исследую / добавлю их.

Ох, и в Свифте ...

blockName = (varName: var_type) -> (return_type)

Это почти как языковая особенность.

Патрик Перини
источник
1
@pcperini Отличный список! И как использовать определение блока typedef в объявлении переменной (1-й элемент в вашем списке)? Логически BlockType ^blockVar = Anonymous Blockпоказывает синтаксическую ошибку, тоже без ^ :(
esp
14
Почему-то мой мозг неспособен запомнить все эти различные синтаксисы для объявлений блоков. Я, наверное, смотрю на этот ответ раз в неделю. Хотел бы я дать вам 10 голосов за это.
Бен Барон
36
Нам нужен Зал славы StackOverflow для ответов на подобные вопросы.
Бежонби
1
Я преобразовал это в Markdown для использования со средством просмотра для печати. Handy! gist.github.com/swizzlr/6268955
Swizzlr
20
Я думаю, что мне нужно это как татуировка.
Исаак Оверекер
83

Мне лично нравится использовать этот сайт ( http://fuckingblocksyntax.com ). Имя легче запомнить, чем сам синтаксис блока:

http://fuckingblocksyntax.com

и если вы не можете загрузить URL с плохими словами в них, вы можете использовать это зеркало: http://goshdarnblocksyntax.com

веб-сайт fuckingblocksyntax

пси
источник
1
идеальное название для сайта ..: D
Vineeth
39

Операторы typedef:

typedef void (^block)(NSString *arg);

В линию:

void (^block)(NSString *) = ^(NSString *param) {
  // do something....
};

Метод:

- (void)method:(void (^)(NSString *param))handler
Эрик Айгнер
источник
Этот ответ показывает, что все не так сложно ... всего лишь 3 различных синтаксиса для смешивания и сопоставления.
Джозеф Чен
4
Принятый ответ - просто копия этого ответа с ненужным раздуванием.
Эрик Эйгнер
16

Библиотека фрагментов Xcode 4 содержит шаблоны для определения типов блоков и встроенных блоков в качестве переменных. Они также доступны через автозаполнение ( typedefblockи inlineblock).

Для блоков в качестве аргументов методов, я бы рекомендовал объявить a, typedefа затем просто использовать это. Это делает код намного проще для чтения.

Объединенные машиностроительные заводы
источник
11

Я написал блок завершения для класса, который будет возвращать значения кубиков после их встряхивания:

  1. Определите typedef с помощью returnType ( .hвышеуказанное @interfaceобъявление)

    typedef void (^CompleteDiceRolling)(NSInteger diceValue);
  2. Определить @propertyдля блока ( .h)

    @property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
  3. Определите метод с помощью finishBlock( .h)

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
  4. Вставьте предыдущий определенный метод в .mфайле и фиксации finishBlockк @propertyопределены до

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
        self.completeDiceRolling = finishBlock;
    }
  5. Для запуска completionBlockпередачи предопределенной переменной типа (не забудьте проверить, completionBlockсуществует ли )

    if( self.completeDiceRolling ){
        self.completeDiceRolling(self.dieValue);
    }
Алекс Чио
источник
7
typedef void (^OkBtnBlock)(id data);
typedef void (^CancelBtnBlock)();

@property (nonatomic, strong) OkBtnBlock okBtnBlock;
@property (nonatomic, strong) CancelBtnBlock cancelBtnBlock;

+ (void)foo:(OkBtnBlock)okBtn andCancel:(CancelBtnBlock)btnCancel;
benhi
источник
Было бы хорошо описать весь процесс шаг за шагом, блоки трудно понять, если вы новичок в ios ...
Алекс Чио
3

Если вам нужно вернуться в Xcode 4.2, вы также можете @synthesize блок, объявленный как свойство, так же, как если бы вы использовали свойство без блока. Не позволяйте синтаксису блока бросить вас.

Если ваше свойство блока это:

@property (copy) return_type (^blockName) (var_type);

Тогда ваш @synthesize это:

@property blockName;

Приветствия.

Алекс Заватоне
источник
Привет, не могли бы вы перепроверить .. Я просто пытался следовать за вами .. @property blockNameне работает. Я думаю, что это должно быть @synthesize blockName;? (для синтеза блока)
jeet.chanchawat
упс ... подождите, вы уже (косвенно) упомянули, что он не будет работать с xcode 7.
jeet.chanchawat