我可以使用Objective-C块作为属性吗?
是否有可能使用标准属性语法块作为属性?
ARC有没有变化?
@property (nonatomic, copy) void (^simpleBlock)(void); @property (nonatomic, copy) BOOL (^blockWithParamter)(NSString *input);
如果你要在几个地方重复同一个块,使用typesdef
typedef void(^MyCompletionBlock)(BOOL success, NSError *error); @property (nonatomic) MyCompletionBlock completion;
下面是一个如何完成这个任务的例子:
#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; }
现在,如果需要更改比较types,唯一需要更改的就是typedef int (^IntBlock)()
。 如果您需要传递两个对象,请将其更改为: typedef int (^IntBlock)(id, id)
,并将您的块更改为:
^ (id obj1, id obj2) { return rand(); };
我希望这有帮助。
编辑2012年3月12日:
对于ARC,无需进行特定更改,因为只要将ARC定义为副本,ARC就会为您pipe理这些块。 你也不需要在你的析构函数中设置属性为零。
如需更多阅读,请参阅此文档: http : //clang.llvm.org/docs/AutomaticReferenceCounting.html
对于Swift,只需使用闭包: 例子。
在Objective-C中,
@属性(副本)无效(^ doStuff)(无效);
就这么简单。
苹果的文档,完全解释了这个问题:
苹果多克。
在你的.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".
这是你的.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(); }
谨防过时的示例代码。
使用现代(2014+)系统,请执行此处显示的内容。 这很简单。 希望它可以帮助别人。 2013年圣诞快乐!
为了后代/完整的缘故…这里有两个完整的例子来说明如何实现这种荒谬的多function的“做事方式”。 @罗伯特的答案是非常简洁和正确的,但是在这里我也想展示实际“定义”块的方法。
@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
愚蠢? 是。 有用? 地狱是啊 这是一个不同的,“更primefaces”的方式来设置属性..和一个非常有用的类…
@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
这说明通过访问器设置块属性(尽pipe在init中,这是一个有争议的冒险行为..)与第一个例子的“非primefaces”“getter”机制。 在这两种情况下,“硬编码”的实现总是可以被覆盖, 每个实例 ..一个lá..
CALayoutDelegator *littleHelper = CALayoutDelegator.new; littleHelper.layoutBlock = ^(CALayer*layer){ [layer.sublayers do:^(id sub){ [sub somethingElseEntirely]; }]; }; someLayer.layoutManager = littleHelper;
另外..如果你想添加一个块属性在一个类别…说你想要使用一个块,而不是一些老派的目标/行动“行动”…你可以使用相关的价值,以及..关联块。
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
现在,当你做一个button的时候,你不必设置一些IBAction
戏剧。只要把创作中要做的工作联系起来…
_button.actionBlock = ^(NSControl*thisButton){ [doc open]; [thisButton setEnabled:NO]; };
这个模式可以应用OVER和OVER到 Cocoa API。 使用属性将代码的相关部分放在一起 ,消除令人费解的委托范例 ,并利用除了仅仅作为哑“容器”之外的对象的能力。
当然,你可以使用块作为属性。 但要确保它们被声明为@property(copy) 。 例如:
typedef void(^TestBlock)(void); @interface SecondViewController : UIViewController @property (nonatomic, copy) TestBlock block; @end
在MRC中,捕获上下文variables的块被分配到堆栈中 ; 堆栈框架被破坏时它们将被释放。 如果它们被复制,一个新的块将被分配到堆中 ,在堆栈帧被调用之后可以被执行。
Disclamer
这并不是要成为“好的答案”,因为这个问题明确地要求ObjectiveC。 正如苹果在WWDC14上介绍了Swift,我想分享一下在Swift中使用block(或闭包)的不同方法。
你好,斯威夫特
你有很多方法可以通过一个相当于Swift函数的块。
我find了三个。
为了理解这一点,我build议你在操场上testing这一小段代码。
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,针对闭包进行了优化
由于Swift针对asynchronous开发进行了优化,因此苹果公司在闭包方面进行了更多的工 首先是function签名可以推断,所以你不必重写它。
通过数字访问参数
let resultShortAnon = test({return "ANON_" + $0 + "__ANON" })
参数推理与命名
let resultShortAnon2 = test({myParam in return "ANON_" + myParam + "__ANON" })
尾随closures
这个特殊情况只有在块是最后一个参数的情况下才起作用,它被称为尾随闭包
这里是一个例子(与推断的签名合并,以显示Swift威力)
let resultTrailingClosure = test { return "TRAILCLOS_" + $0 + "__TRAILCLOS" }
最后:
使用所有这些function,我会做的是混合尾随封闭和types推断(命名为了可读性)
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!") } }
你好,斯威夫特
作为@Francescu回答的补充。
添加额外的参数:
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)
您可以按照下面的格式使用类中的testingObjectiveCBlock
属性。
typedef void (^testingObjectiveCBlock)(NSString *errorMsg); @interface MyClass : NSObject @property (nonatomic, strong) testingObjectiveCBlock testingObjectiveCBlock; @end
欲了解更多信息,请看这里