Is it possible to have blocks as properties using the standard property syntax?
是否可以使用标准的属性语法将块作为属性?
Are there any changes for ARC?
弧形有什么变化吗?
8 个解决方案
#1
271
@property (nonatomic, copy) void (^simpleBlock)(void);
@property (nonatomic, copy) BOOL (^blockWithParamter)(NSString *input);
If you are going to be repeating the same block in several places use a type def
如果你要在几个地方重复相同的块,使用类型def。
typedef void(^MyCompletionBlock)(BOOL success, NSError *error);
@property (nonatomic) MyCompletionBlock completion;
#2
210
Here's an example of how you would accomplish such a task:
这里有一个你如何完成这样一项任务的例子:
#import <Foundation/Foundation.h>
typedef int (^IntBlock)();
@interface myobj : NSObject
{
IntBlock compare;
}
@property(readwrite, copy) IntBlock compare;
@end
@implementation myobj
@synthesize compare;
- (void)dealloc
{
// need to release the block since the property was declared copy. (for heap
// allocated blocks this prevents a potential leak, for compiler-optimized
// stack blocks it is a no-op)
// Note that for ARC, this is unnecessary, as with all properties, the memory management is handled for you.
[compare release];
[super dealloc];
}
@end
int main () {
@autoreleasepool {
myobj *ob = [[myobj alloc] init];
ob.compare = ^
{
return rand();
};
NSLog(@"%i", ob.compare());
// if not ARC
[ob release];
}
return 0;
}
Now, the only thing that would need to change if you needed to change the type of compare would be the typedef int (^IntBlock)()
. If you need to pass two objects to it, change it to this: typedef int (^IntBlock)(id, id)
, and change your block to:
现在,唯一需要改变如果你需要改变比较的类型是int类型定义(^ IntBlock)()。如果你需要两个对象传递给它,改变它:typedef int(^ IntBlock)(id,id),和改变你的块:
^ (id obj1, id obj2)
{
return rand();
};
I hope this helps.
我希望这可以帮助。
EDIT March 12, 2012:
2012年3月12日,编辑:
For ARC, there are no specific changes required, as ARC will manage the blocks for you as long as they are defined as copy. You do not need to set the property to nil in your destructor, either.
对于ARC,不需要任何特定的更改,因为只要将它们定义为copy, ARC就会为您管理这些块。也不需要在析构函数中将属性设置为nil。
For more reading, please check out this document: http://clang.llvm.org/docs/AutomaticReferenceCounting.html
更多阅读,请查看此文档:http://clang.llvm.org/docs/AutomaticReferenceCounting.html
#3
152
For Swift, just use closures: example.
对于Swift,只需使用闭包:示例。
In Objective-C,
在objective - c中,
@property (copy)void (^doStuff)(void);
It's that simple.
就是这么简单。
Apple's documentation, fully explaining this issue:
苹果doco。
In your .h file:
. h文件中:
// Here is a block as a property:
//
// Someone passes you a block. You "hold on to it",
// while you do other stuff. Later, you use the block.
//
// The property 'doStuff' will hold the incoming block.
@property (copy)void (^doStuff)(void);
// Here's a method in your class.
// When someone CALLS this method, they PASS IN a block of code,
// which they want to be performed after the method is finished.
-(void)doSomethingAndThenDoThis:(void(^)(void))pleaseDoMeLater;
// We will hold on to that block of code in "doStuff".
Here's your .m file:
这是你的m文件:
-(void)doSomethingAndThenDoThis:(void(^)(void))pleaseDoMeLater
{
// Regarding the incoming block of code, save it for later:
self.doStuff = pleaseDoMeLater;
// Now do other processing, which could follow various paths,
// involve delays, and so on. Then after everything:
[self _alldone];
}
-(void)_alldone
{
NSLog(@"Processing finished, running the completion block.");
// Here's how to run the block:
if ( self.doStuff != nil )
self.doStuff();
}
Beware of out-of-date example code.
With modern (2014+) systems, do what is shown here. It is that simple. Hope it helps someone. Merry Christmas 2013!
使用现代(2014+)系统,按这里显示的那样做。它就是这么简单。希望它能帮助一些人。2013年圣诞节快乐!
#4
18
For posterity / completeness's sake… Here are two FULL examples of how to implement this ridiculously versatile "way of doing things". @Robert's answer is blissfully concise and correct, but here I want to also show ways to actually "define" the blocks.
为了子孙后代/完整性,这里有两个完整的例子来说明如何实现这种荒谬的“做事方式”。@Robert的回答非常简洁和正确,但在这里我也想展示一些实际“定义”块的方法。
@interface ReusableClass : NSObject
@property (nonatomic,copy) CALayer*(^layerFromArray)(NSArray*);
@end
@implementation ResusableClass
static NSString const * privateScope = @"Touch my monkey.";
- (CALayer*(^)(NSArray*)) layerFromArray {
return ^CALayer*(NSArray* array){
CALayer *returnLayer = CALayer.layer
for (id thing in array) {
[returnLayer doSomethingCrazy];
[returnLayer setValue:privateScope
forKey:@"anticsAndShenanigans"];
}
return list;
};
}
@end
Silly? Yes. Useful? Hells yeah. Here is a different, "more atomic" way of setting the property.. and a class that is ridiculously useful…
傻吗?是的。有用吗?地狱啊。这里有一种不同的,“更原子化”的方法来设置属性。一个非常有用的类……
@interface CALayoutDelegator : NSObject
@property (nonatomic,strong) void(^layoutBlock)(CALayer*);
@end
@implementation CALayoutDelegator
- (id) init {
return self = super.init ?
[self setLayoutBlock: ^(CALayer*layer){
for (CALayer* sub in layer.sublayers)
[sub someDefaultLayoutRoutine];
}], self : nil;
}
- (void) layoutSublayersOfLayer:(CALayer*)layer {
self.layoutBlock ? self.layoutBlock(layer) : nil;
}
@end
This illustrates setting the block property via the accessor (albeit inside init, a debatably dicey practice..) vs the first example's "nonatomic" "getter" mechanism. In either case… the "hardcoded" implementations can always be overwritten, per instance.. a lá..
这说明了如何通过访问器(尽管在init中,这是一个有争议的冒险实践..)和第一个示例的“非原子”“getter”机制来设置块属性。无论哪种情况,“硬编码”实现总是可以被覆盖,每个实例。一个拉. .
CALayoutDelegator *littleHelper = CALayoutDelegator.new;
littleHelper.layoutBlock = ^(CALayer*layer){
[layer.sublayers do:^(id sub){ [sub somethingElseEntirely]; }];
};
someLayer.layoutManager = littleHelper;
Also.. if you want to add a block property in a category... say you want to use a Block instead of some old-school target / action "action"... You can just use associated values to, well.. associate the blocks.
也. .如果您想在一个类别中添加块属性……说你想用一个Block而不是一些老派的目标/行动“action”……你可以使用关联值。把块。
typedef void(^NSControlActionBlock)(NSControl*);
@interface NSControl (ActionBlocks)
@property (copy) NSControlActionBlock actionBlock; @end
@implementation NSControl (ActionBlocks)
- (NSControlActionBlock) actionBlock {
// use the "getter" method's selector to store/retrieve the block!
return objc_getAssociatedObject(self, _cmd);
}
- (void) setActionBlock:(NSControlActionBlock)ab {
objc_setAssociatedObject( // save (copy) the block associatively, as categories can't synthesize Ivars.
self, @selector(actionBlock),ab ,OBJC_ASSOCIATION_COPY);
self.target = self; // set self as target (where you call the block)
self.action = @selector(doItYourself); // this is where it's called.
}
- (void) doItYourself {
if (self.actionBlock && self.target == self) self.actionBlock(self);
}
@end
Now, when you make a button, you don't have to set up some IBAction
drama.. Just associate the work to be done at creation...
现在,当你做一个按钮,你不需要设置一些IBAction戏剧。只要把创造时要做的工作联系起来……
_button.actionBlock = ^(NSControl*thisButton){
[doc open]; [thisButton setEnabled:NO];
};
This pattern can be applied OVER and OVER to Cocoa API's. Use properties to bring the relevant parts of your code closer together, eliminate convoluted delegation paradigms, and leverage the power of objects beyond that of just acting as dumb "containers".
这种模式可以应用到Cocoa API中。使用属性使代码的相关部分更紧密地结合在一起,消除复杂的委托范例,并利用对象的力量,而不仅仅是充当愚蠢的“容器”。
#5
8
Of course you could use blocks as properties. But make sure they are declared as @property(copy). For example:
当然,您可以使用块作为属性。但是要确保它们被声明为@property(copy)。例如:
typedef void(^TestBlock)(void);
@interface SecondViewController : UIViewController
@property (nonatomic, copy) TestBlock block;
@end
In MRC, blocks capturing context variables are allocated in stack; they will be released when the stack frame is destroyed. If they are copied, a new block will be allocated in heap, which can be executed later on after the stack frame is poped.
在MRC中,在堆栈中分配捕获上下文变量的块;当堆栈帧被销毁时,它们将被释放。如果复制它们,那么将在堆中分配一个新的块,可以在堆栈框架弹出后稍后执行。
#6
7
Disclamer
This is not intended to be "the good answer", as this question ask explicitly for ObjectiveC. As Apple introduced Swift at the WWDC14, I'd like to share the different ways to use block (or closures) in Swift.
这并不是“好的答案”,因为这个问题明确地问了objective - ec。当苹果在WWDC14上介绍Swift时,我想在Swift中分享使用块(或闭包)的不同方式。
Hello, Swift
You have many ways offered to pass a block equivalent to function in Swift.
你有很多方法来传递一个相当于Swift函数的块。
I found three.
我找到了三个。
To understand this I suggest you to test in playground this little piece of code.
为了理解这一点,我建议你在操场上测试这一小段代码。
func test(function:String -> String) -> String
{
return function("test")
}
func funcStyle(s:String) -> String
{
return "FUNC__" + s + "__FUNC"
}
let resultFunc = test(funcStyle)
let blockStyle:(String) -> String = {s in return "BLOCK__" + s + "__BLOCK"}
let resultBlock = test(blockStyle)
let resultAnon = test({(s:String) -> String in return "ANON_" + s + "__ANON" })
println(resultFunc)
println(resultBlock)
println(resultAnon)
Swift, optimized for closures
As Swift is optimized for asynchronous development, Apple worked more on closures. The first is that function signature can be inferred so you don't have to rewrite it.
由于Swift针对异步开发进行了优化,苹果在闭包方面做了更多的工作。首先,可以推断函数签名,这样就不必重写了。
Access params by numbers
let resultShortAnon = test({return "ANON_" + $0 + "__ANON" })
Params inference with naming
let resultShortAnon2 = test({myParam in return "ANON_" + myParam + "__ANON" })
Trailing Closure
This special case works only if the block is the last argument, it's called trailing closure
这种特殊情况仅在块是最后一个参数时才有效,称为尾闭包
Here is an example (merged with inferred signature to show Swift power)
这里有一个例子(合并了推断签名以显示快速的力量)
let resultTrailingClosure = test { return "TRAILCLOS_" + $0 + "__TRAILCLOS" }
Finally:
最后:
Using all this power what I'd do is mixing trailing closure and type inference (with naming for readability)
使用所有这些功能,我要做的就是混合尾闭包和类型推断(为可读性命名)
PFFacebookUtils.logInWithPermissions(permissions) {
user, error in
if (!user) {
println("Uh oh. The user cancelled the Facebook login.")
} else if (user.isNew) {
println("User signed up and logged in through Facebook!")
} else {
println("User logged in through Facebook!")
}
}
#7
0
Hello, Swift
你好,迅速
Complementing what @Francescu answered.
补充什么@Francescu回答。
Adding extra parameters:
添加额外的参数:
func test(function:String -> String, param1:String, param2:String) -> String
{
return function("test"+param1 + param2)
}
func funcStyle(s:String) -> String
{
return "FUNC__" + s + "__FUNC"
}
let resultFunc = test(funcStyle, "parameter 1", "parameter 2")
let blockStyle:(String) -> String = {s in return "BLOCK__" + s + "__BLOCK"}
let resultBlock = test(blockStyle, "parameter 1", "parameter 2")
let resultAnon = test({(s:String) -> String in return "ANON_" + s + "__ANON" }, "parameter 1", "parameter 2")
println(resultFunc)
println(resultBlock)
println(resultAnon)
#8
-3
You can follow the format below and can use the testingObjectiveCBlock
property in the class.
您可以遵循下面的格式,并可以在类中使用testingObjectiveCBlock属性。
typedef void (^testingObjectiveCBlock)(NSString *errorMsg);
@interface MyClass : NSObject
@property (nonatomic, strong) testingObjectiveCBlock testingObjectiveCBlock;
@end
For more info have a look here
更多信息,请看这里
#1
271
@property (nonatomic, copy) void (^simpleBlock)(void);
@property (nonatomic, copy) BOOL (^blockWithParamter)(NSString *input);
If you are going to be repeating the same block in several places use a type def
如果你要在几个地方重复相同的块,使用类型def。
typedef void(^MyCompletionBlock)(BOOL success, NSError *error);
@property (nonatomic) MyCompletionBlock completion;
#2
210
Here's an example of how you would accomplish such a task:
这里有一个你如何完成这样一项任务的例子:
#import <Foundation/Foundation.h>
typedef int (^IntBlock)();
@interface myobj : NSObject
{
IntBlock compare;
}
@property(readwrite, copy) IntBlock compare;
@end
@implementation myobj
@synthesize compare;
- (void)dealloc
{
// need to release the block since the property was declared copy. (for heap
// allocated blocks this prevents a potential leak, for compiler-optimized
// stack blocks it is a no-op)
// Note that for ARC, this is unnecessary, as with all properties, the memory management is handled for you.
[compare release];
[super dealloc];
}
@end
int main () {
@autoreleasepool {
myobj *ob = [[myobj alloc] init];
ob.compare = ^
{
return rand();
};
NSLog(@"%i", ob.compare());
// if not ARC
[ob release];
}
return 0;
}
Now, the only thing that would need to change if you needed to change the type of compare would be the typedef int (^IntBlock)()
. If you need to pass two objects to it, change it to this: typedef int (^IntBlock)(id, id)
, and change your block to:
现在,唯一需要改变如果你需要改变比较的类型是int类型定义(^ IntBlock)()。如果你需要两个对象传递给它,改变它:typedef int(^ IntBlock)(id,id),和改变你的块:
^ (id obj1, id obj2)
{
return rand();
};
I hope this helps.
我希望这可以帮助。
EDIT March 12, 2012:
2012年3月12日,编辑:
For ARC, there are no specific changes required, as ARC will manage the blocks for you as long as they are defined as copy. You do not need to set the property to nil in your destructor, either.
对于ARC,不需要任何特定的更改,因为只要将它们定义为copy, ARC就会为您管理这些块。也不需要在析构函数中将属性设置为nil。
For more reading, please check out this document: http://clang.llvm.org/docs/AutomaticReferenceCounting.html
更多阅读,请查看此文档:http://clang.llvm.org/docs/AutomaticReferenceCounting.html
#3
152
For Swift, just use closures: example.
对于Swift,只需使用闭包:示例。
In Objective-C,
在objective - c中,
@property (copy)void (^doStuff)(void);
It's that simple.
就是这么简单。
Apple's documentation, fully explaining this issue:
苹果doco。
In your .h file:
. h文件中:
// Here is a block as a property:
//
// Someone passes you a block. You "hold on to it",
// while you do other stuff. Later, you use the block.
//
// The property 'doStuff' will hold the incoming block.
@property (copy)void (^doStuff)(void);
// Here's a method in your class.
// When someone CALLS this method, they PASS IN a block of code,
// which they want to be performed after the method is finished.
-(void)doSomethingAndThenDoThis:(void(^)(void))pleaseDoMeLater;
// We will hold on to that block of code in "doStuff".
Here's your .m file:
这是你的m文件:
-(void)doSomethingAndThenDoThis:(void(^)(void))pleaseDoMeLater
{
// Regarding the incoming block of code, save it for later:
self.doStuff = pleaseDoMeLater;
// Now do other processing, which could follow various paths,
// involve delays, and so on. Then after everything:
[self _alldone];
}
-(void)_alldone
{
NSLog(@"Processing finished, running the completion block.");
// Here's how to run the block:
if ( self.doStuff != nil )
self.doStuff();
}
Beware of out-of-date example code.
With modern (2014+) systems, do what is shown here. It is that simple. Hope it helps someone. Merry Christmas 2013!
使用现代(2014+)系统,按这里显示的那样做。它就是这么简单。希望它能帮助一些人。2013年圣诞节快乐!
#4
18
For posterity / completeness's sake… Here are two FULL examples of how to implement this ridiculously versatile "way of doing things". @Robert's answer is blissfully concise and correct, but here I want to also show ways to actually "define" the blocks.
为了子孙后代/完整性,这里有两个完整的例子来说明如何实现这种荒谬的“做事方式”。@Robert的回答非常简洁和正确,但在这里我也想展示一些实际“定义”块的方法。
@interface ReusableClass : NSObject
@property (nonatomic,copy) CALayer*(^layerFromArray)(NSArray*);
@end
@implementation ResusableClass
static NSString const * privateScope = @"Touch my monkey.";
- (CALayer*(^)(NSArray*)) layerFromArray {
return ^CALayer*(NSArray* array){
CALayer *returnLayer = CALayer.layer
for (id thing in array) {
[returnLayer doSomethingCrazy];
[returnLayer setValue:privateScope
forKey:@"anticsAndShenanigans"];
}
return list;
};
}
@end
Silly? Yes. Useful? Hells yeah. Here is a different, "more atomic" way of setting the property.. and a class that is ridiculously useful…
傻吗?是的。有用吗?地狱啊。这里有一种不同的,“更原子化”的方法来设置属性。一个非常有用的类……
@interface CALayoutDelegator : NSObject
@property (nonatomic,strong) void(^layoutBlock)(CALayer*);
@end
@implementation CALayoutDelegator
- (id) init {
return self = super.init ?
[self setLayoutBlock: ^(CALayer*layer){
for (CALayer* sub in layer.sublayers)
[sub someDefaultLayoutRoutine];
}], self : nil;
}
- (void) layoutSublayersOfLayer:(CALayer*)layer {
self.layoutBlock ? self.layoutBlock(layer) : nil;
}
@end
This illustrates setting the block property via the accessor (albeit inside init, a debatably dicey practice..) vs the first example's "nonatomic" "getter" mechanism. In either case… the "hardcoded" implementations can always be overwritten, per instance.. a lá..
这说明了如何通过访问器(尽管在init中,这是一个有争议的冒险实践..)和第一个示例的“非原子”“getter”机制来设置块属性。无论哪种情况,“硬编码”实现总是可以被覆盖,每个实例。一个拉. .
CALayoutDelegator *littleHelper = CALayoutDelegator.new;
littleHelper.layoutBlock = ^(CALayer*layer){
[layer.sublayers do:^(id sub){ [sub somethingElseEntirely]; }];
};
someLayer.layoutManager = littleHelper;
Also.. if you want to add a block property in a category... say you want to use a Block instead of some old-school target / action "action"... You can just use associated values to, well.. associate the blocks.
也. .如果您想在一个类别中添加块属性……说你想用一个Block而不是一些老派的目标/行动“action”……你可以使用关联值。把块。
typedef void(^NSControlActionBlock)(NSControl*);
@interface NSControl (ActionBlocks)
@property (copy) NSControlActionBlock actionBlock; @end
@implementation NSControl (ActionBlocks)
- (NSControlActionBlock) actionBlock {
// use the "getter" method's selector to store/retrieve the block!
return objc_getAssociatedObject(self, _cmd);
}
- (void) setActionBlock:(NSControlActionBlock)ab {
objc_setAssociatedObject( // save (copy) the block associatively, as categories can't synthesize Ivars.
self, @selector(actionBlock),ab ,OBJC_ASSOCIATION_COPY);
self.target = self; // set self as target (where you call the block)
self.action = @selector(doItYourself); // this is where it's called.
}
- (void) doItYourself {
if (self.actionBlock && self.target == self) self.actionBlock(self);
}
@end
Now, when you make a button, you don't have to set up some IBAction
drama.. Just associate the work to be done at creation...
现在,当你做一个按钮,你不需要设置一些IBAction戏剧。只要把创造时要做的工作联系起来……
_button.actionBlock = ^(NSControl*thisButton){
[doc open]; [thisButton setEnabled:NO];
};
This pattern can be applied OVER and OVER to Cocoa API's. Use properties to bring the relevant parts of your code closer together, eliminate convoluted delegation paradigms, and leverage the power of objects beyond that of just acting as dumb "containers".
这种模式可以应用到Cocoa API中。使用属性使代码的相关部分更紧密地结合在一起,消除复杂的委托范例,并利用对象的力量,而不仅仅是充当愚蠢的“容器”。
#5
8
Of course you could use blocks as properties. But make sure they are declared as @property(copy). For example:
当然,您可以使用块作为属性。但是要确保它们被声明为@property(copy)。例如:
typedef void(^TestBlock)(void);
@interface SecondViewController : UIViewController
@property (nonatomic, copy) TestBlock block;
@end
In MRC, blocks capturing context variables are allocated in stack; they will be released when the stack frame is destroyed. If they are copied, a new block will be allocated in heap, which can be executed later on after the stack frame is poped.
在MRC中,在堆栈中分配捕获上下文变量的块;当堆栈帧被销毁时,它们将被释放。如果复制它们,那么将在堆中分配一个新的块,可以在堆栈框架弹出后稍后执行。
#6
7
Disclamer
This is not intended to be "the good answer", as this question ask explicitly for ObjectiveC. As Apple introduced Swift at the WWDC14, I'd like to share the different ways to use block (or closures) in Swift.
这并不是“好的答案”,因为这个问题明确地问了objective - ec。当苹果在WWDC14上介绍Swift时,我想在Swift中分享使用块(或闭包)的不同方式。
Hello, Swift
You have many ways offered to pass a block equivalent to function in Swift.
你有很多方法来传递一个相当于Swift函数的块。
I found three.
我找到了三个。
To understand this I suggest you to test in playground this little piece of code.
为了理解这一点,我建议你在操场上测试这一小段代码。
func test(function:String -> String) -> String
{
return function("test")
}
func funcStyle(s:String) -> String
{
return "FUNC__" + s + "__FUNC"
}
let resultFunc = test(funcStyle)
let blockStyle:(String) -> String = {s in return "BLOCK__" + s + "__BLOCK"}
let resultBlock = test(blockStyle)
let resultAnon = test({(s:String) -> String in return "ANON_" + s + "__ANON" })
println(resultFunc)
println(resultBlock)
println(resultAnon)
Swift, optimized for closures
As Swift is optimized for asynchronous development, Apple worked more on closures. The first is that function signature can be inferred so you don't have to rewrite it.
由于Swift针对异步开发进行了优化,苹果在闭包方面做了更多的工作。首先,可以推断函数签名,这样就不必重写了。
Access params by numbers
let resultShortAnon = test({return "ANON_" + $0 + "__ANON" })
Params inference with naming
let resultShortAnon2 = test({myParam in return "ANON_" + myParam + "__ANON" })
Trailing Closure
This special case works only if the block is the last argument, it's called trailing closure
这种特殊情况仅在块是最后一个参数时才有效,称为尾闭包
Here is an example (merged with inferred signature to show Swift power)
这里有一个例子(合并了推断签名以显示快速的力量)
let resultTrailingClosure = test { return "TRAILCLOS_" + $0 + "__TRAILCLOS" }
Finally:
最后:
Using all this power what I'd do is mixing trailing closure and type inference (with naming for readability)
使用所有这些功能,我要做的就是混合尾闭包和类型推断(为可读性命名)
PFFacebookUtils.logInWithPermissions(permissions) {
user, error in
if (!user) {
println("Uh oh. The user cancelled the Facebook login.")
} else if (user.isNew) {
println("User signed up and logged in through Facebook!")
} else {
println("User logged in through Facebook!")
}
}
#7
0
Hello, Swift
你好,迅速
Complementing what @Francescu answered.
补充什么@Francescu回答。
Adding extra parameters:
添加额外的参数:
func test(function:String -> String, param1:String, param2:String) -> String
{
return function("test"+param1 + param2)
}
func funcStyle(s:String) -> String
{
return "FUNC__" + s + "__FUNC"
}
let resultFunc = test(funcStyle, "parameter 1", "parameter 2")
let blockStyle:(String) -> String = {s in return "BLOCK__" + s + "__BLOCK"}
let resultBlock = test(blockStyle, "parameter 1", "parameter 2")
let resultAnon = test({(s:String) -> String in return "ANON_" + s + "__ANON" }, "parameter 1", "parameter 2")
println(resultFunc)
println(resultBlock)
println(resultAnon)
#8
-3
You can follow the format below and can use the testingObjectiveCBlock
property in the class.
您可以遵循下面的格式,并可以在类中使用testingObjectiveCBlock属性。
typedef void (^testingObjectiveCBlock)(NSString *errorMsg);
@interface MyClass : NSObject
@property (nonatomic, strong) testingObjectiveCBlock testingObjectiveCBlock;
@end
For more info have a look here
更多信息,请看这里