是否可以使用标准属性语法将块作为属性?
ARC 有哪些变化?
是否可以使用标准属性语法将块作为属性?
ARC 有哪些变化?
@property (nonatomic, copy) void (^simpleBlock)(void);
@property (nonatomic, copy) BOOL (^blockWithParamter)(NSString *input);
如果你要在多个地方重复使用相同的代码块,可以使用类型定义(type def)。
typedef void(^MyCompletionBlock)(BOOL success, NSError *error);
@property (nonatomic) MyCompletionBlock completion;
@synthesize
,默认情况下就是你现在所做的 @synthesize name = _name;
。https://dev59.com/SmfWa4cB1Zd3GeqPja0E#12119360 - Eric下面是如何完成这样的任务的示例:
#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;
}
现在,如果你需要改变比较的类型,唯一需要更改的是typedef int (^IntBlock)()
。如果你需要传递两个对象给它,将其更改为:typedef int (^IntBlock)(id, id)
,然后将你的块更改为:
^ (id obj1, id obj2)
{
return rand();
};
2012年3月12日编辑:
对于ARC来说,不需要进行特定的更改,只要它们被定义为copy,ARC将为您管理块。在析构函数中,您也不需要将属性设置为nil。
如需更多阅读,请查看此文档: http://clang.llvm.org/docs/AutomaticReferenceCounting.html
@property (copy)void (^doStuff)(void);
您的.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年及以后)的系统,这是正确的和被记录的方法。
nonatomic
吗? - Alex Pretzlav为了记录完整性,以下是两个完整的示例,展示如何实现这种极其灵活的“事情处理方式”。@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
看起来有点傻?是的。 但是有用吗?当然了。 这里有一种不同的、"更原子化"的设置属性的方式...以及一个非常有用的类...
@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
这说明了通过访问器(虽然在init内部,这是一个有争议的做法..)设置块属性与第一个示例中的“nonatomic”“getter”机制。 在任一情况下...硬编码的实现始终可以被覆盖,每个实例都可以进行...
CALayoutDelegator *littleHelper = CALayoutDelegator.new;
littleHelper.layoutBlock = ^(CALayer*layer){
[layer.sublayers do:^(id sub){ [sub somethingElseEntirely]; }];
};
someLayer.layoutManager = littleHelper;
另外,如果您想在类别中添加块属性...例如,您想使用块代替某些老式的目标/操作"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
IBAction
的操作。只需在创建时将要执行的工作关联起来即可。_button.actionBlock = ^(NSControl*thisButton){
[doc open]; [thisButton setEnabled:NO];
};
这种模式可以应用于Cocoa API的各个方面。使用属性将代码中相关部分“聚合”在一起,消除复杂的委托范式,并利用对象的能力,超越仅充当“容器”的作用。
typedef void(^TestBlock)(void);
@interface SecondViewController : UIViewController
@property (nonatomic, copy) TestBlock block;
@end
本文旨在为需要Objective-C的人提供帮助,但由于苹果在WWDC14上推出了Swift,因此我想分享在Swift中使用块(或闭包)的不同方法。这并不意味着这是唯一正确的答案。
在Swift中,你有多种方式来传递一个类似于函数的块。
我发现了三种方法。
为了更好地理解,建议在playground中测试以下代码片段。
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针对异步开发进行了优化,因此苹果公司更加注重闭包的使用。 第一个优化是函数签名可以被推断,因此您不必重新编写它。
let resultShortAnon = test({return "ANON_" + $0 + "__ANON" })
let resultShortAnon2 = test({myParam in return "ANON_" + myParam + "__ANON" })
只有当块作为最后一个参数时,这种特殊情况才适用,它被称为“尾随闭包”
以下是一个示例(与推断签名合并以展示Swift的强大功能)
let resultTrailingClosure = test { return "TRAILCLOS_" + $0 + "__TRAILCLOS" }
最后:
利用所有这些技术,我会混合使用尾随闭包和类型推断(并进行命名以提高可读性)。
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!")
}
}
你好,Swift
补充@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
欲了解更多信息,请查看此处