块声明语法列表

282

Objective-C中的块语法(以及我假设的C语言)非常不协调。将块作为参数传递与声明块作为实例变量不同,这与使用typedef定义块不同。

是否有一个全面的块声明语法列表可供参考?


9
在Blocks编程主题指南中,"声明和创建Blocks"有什么问题? - jscs
使用块属性的简单解释:https://dev59.com/Jm865IYBdhLWcg3wM7u0#20760583 - Fattie
7个回答

700

块声明语法列表

在整个过程中,让:

  • 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);

返回 Blocks

一个方法可以返回一个 block,

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

如果有点奇怪的话,函数也可以这样做。

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

附加说明

如果我遗漏了任何内容,请在评论中告诉我,我会进行研究并添加它们。

哦,还有在Swift中...

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

这几乎就像是一种语言特性。


14
不知怎的,我的大脑无法记住所有这些不同的块声明语法。我大概每周都要看一次这个答案。真希望我能为你的回答点赞十次。 - Ben Baron
37
我们需要一个类似于 StackOverflow 名人堂的东西,来表彰像这样优秀的答案。 - Jonathan Beebe
1
我已将此转换为Markdown格式,以便使用查看器进行打印。非常方便!https://gist.github.com/swizzlr/6268955 - Swizzlr
22
我想把这个纹身在身上。 - Isaac Overacker
1
如果您像Ben (einsteinx2)一样经常使用它,我建议将其复制到某个文本文件中,并在变量周围加上"<#"和"#>",这样当您复制和粘贴时,Xcode会将它们视为占位符。 --来自匹兹堡的Rob - Rob at TVSeries.com
显示剩余9条评论

87

3
完美的网站名称.. :D - Vineeth

41

类型定义:

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

内联:

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

方法:

- (void)method:(void (^)(NSString *param))handler

这个答案表明,其实并不那么复杂...只需要混合和匹配3种不同的语法即可。 - Joseph Chen
4
接受的答案只是这个答案的冗余副本,没有必要的浮肿。 - user187676

16

Xcode 4的片段库中包含用于块typedef和作为变量的内联块的模板。它们还可以通过自动补全(typedefblockinlineblock)使用。

对于作为方法参数的块,我建议声明一个typedef,然后简单地使用它。这使得代码更易于阅读。


12

我为一个类编写了一个completionBlock,它将在摇动骰子后返回其值:

  1. @interface 声明上方的 .h 文件中定义带有返回类型的 typedef。

typedef void (^CompleteDiceRolling)(NSInteger diceValue);
  • 在块的.h文件中定义一个@property

  • @property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
    
    定义一个具有finishBlock方法的函数(.h)。
    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
    
    将之前定义的方法插入到 .m 文件中,并将 finishBlock 提交给之前定义的 @property
    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
        self.completeDiceRolling = finishBlock;
    }
    
  • 为了触发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;
    

    最好逐步描述整个过程,如果您是iOS新手,则很难理解块。 - Alex Cio

    3
    如果您需要在Xcode 4.2中工作,则可以像非块属性一样@synthesize声明为属性的块。不要让块语法困扰您。
    如果您的块属性是这样的:
    @property (copy) return_type (^blockName) (var_type);
    

    然后你的 @synthesize 代码是这样的:
    @property blockName;
    

    欢呼。

    你好,能否请您重新检查一下?我刚刚试着跟随您的步骤,但是 @property blockName 没有起作用。我认为应该是 @synthesize blockName; 才对(用于合成一个 block)。 - jeet.chanchawat
    糟糕...等等,你已经(间接地)提到它不能与Xcode 7一起使用了。 - jeet.chanchawat

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接