Список синтаксису оголошень блоку


277

Синтаксис блоку в об'єктиві C (і справді C, я припускаю), як відомо, не є несумісним. Передача блоків як аргументів виглядає інакше, ніж оголошення блоків як ivars, що виглядає інакше, ніж typedefing блоків.

Чи є вичерпний список синтаксису блок-декларацій, який я міг би тримати під рукою для швидкого довідки?


9
Що не так із "Об'явлення та створення блоків" у Посібнику з програм програмування блоків?
jscs

відверте пояснення використання властивостей блоку: stackoverflow.com/a/20760583/294884
Fattie

Відповіді:


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. Цей метод інстанції не містить циклів утримування в АРК.

__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'd блоку у оголошенні змінної (1-й елемент у вашому списку)? Логічні BlockType ^blockVar = Anonymous Blockпоказують синтаксичну помилку, без ^ теж :(
esp

14
Якось мій мозок нездатний запам’ятати всі ці різні синтаксиси для блокових оголошень. Я, мабуть, дивлюсь на цю відповідь раз на тиждень. Бажаю, щоб я міг дати вам 10 грошей за це.
Бен Барон

36
Для такої відповіді нам потрібен Зал слави StackOverflow.
bejonbee

1
Я перетворив це в Markdown для використання з переглядачем друку. Зручно! gist.github.com/swizzlr/6268955
Swizzlr

20
Я думаю, мені це потрібно як татуювання.
Ісаак Оверкер

83

Мені особисто подобається використовувати цей веб-сайт ( http://fuckingblocksyntax.com ). Ім'я легше запам’ятати, ніж сам синтаксис блоку:

http://fuckingblocksyntax.com

і якщо ви не можете завантажити URL-адреси з поганими словами, ви можете скористатися цим дзеркалом: http://goshdarnblocksyntax.com

вебсайт


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 містить шаблони для блоків typedefs та вбудованих блоків як змінних. Вони також доступні через автоматичне завершення ( 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передачі до нього заздалегідь визначеної змінноїType (Не забудьте перевірити, чи 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;

Було б добре описати весь процес крок за кроком, блоки важко зрозуміти, якщо ви новачок у ios ...
Alex

3

Якщо вам потрібно знову працювати в Xcode 4.2, ви також можете @synthesize блок, оголошений як властивість так само, як і з неблоковим властивістю. Не дозволяйте синтаксису блоків кинути вас.

Якщо ваша властивість блоку така:

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

Тоді ваш @synthesize такий:

@property blockName;

Ура.


Привіт, ви можете, будь ласка, повторно перевірити .. Я просто намагався слідкувати за вами .. @property blockNameне працює. Я думаю, що має бути @synthesize blockName;? (для синтезу блоку)
jeet.chanchawat

oops ... зачекайте, ви вже (побічно) згадали, що це не буде працювати з xcode 7.
jeet.chanchawat
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.