Ios 我可以使用Objective-C块作为属性吗?

Ios 我可以使用Objective-C块作为属性吗?,ios,objective-c,automatic-ref-counting,objective-c-blocks,Ios,Objective C,Automatic Ref Counting,Objective C Blocks,是否可以使用标准属性语法将块作为属性 ARC是否有任何变化?以下是您如何完成此任务的示例: #import <Foundation/Foundation.h> typedef int (^IntBlock)(); @interface myobj : NSObject { IntBlock compare; } @property(readwrite, copy) IntBlock compare; @end @implementation myobj @synth

是否可以使用标准属性语法将块作为属性


ARC是否有任何变化?

以下是您如何完成此任务的示例:

#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;
}
我希望这有帮助

2012年3月12日编辑:

对于ARC,不需要进行任何特定更改,因为只要将块定义为“复制”,ARC将为您管理这些块。您也不需要在析构函数中将属性设置为nil

如需更多阅读,请查看此文档:

如果要在多个位置重复同一块,请使用def类型

typedef void(^MyCompletionBlock)(BOOL success, NSError *error);
@property (nonatomic) MyCompletionBlock completion;

为了子孙后代/完整性的缘故……这里有两个完整的例子,说明如何实现这种可笑的多功能“做事方式”@罗伯特的回答非常简洁和正确,但在这里我还想展示实际“定义”块的方法

@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内部,这是一种值得商榷的做法…),而不是第一个示例的“非原子”getter机制。在任何一种情况下,每个实例的“硬编码”实现都可以被覆盖。。a拉

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
现在,当您制作一个按钮时,您不必设置一些
iAction
戏剧。。只需将创建时要完成的工作关联起来

_button.actionBlock = ^(NSControl*thisButton){ 

     [doc open]; [thisButton setEnabled:NO]; 
};

此模式可以反复应用于Cocoa API。使用属性将代码的相关部分更紧密地结合在一起,消除复杂的委托范例,并利用对象的功能,而不仅仅是充当愚蠢的“容器”。

对于Swift,只需使用闭包:


在目标C中:

@财产(副本)无效 就这么简单

以下是实际的苹果文档,它精确地说明了使用什么:

在.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+)系统,执行此处显示的操作。就这么简单

您可以遵循以下格式,并可以在类中使用
testingObjectiveBlock
属性

typedef void (^testingObjectiveCBlock)(NSString *errorMsg);

@interface MyClass : NSObject
@property (nonatomic, strong) testingObjectiveCBlock testingObjectiveCBlock;
@end
有关更多信息,请查看Disclamer 这并不是“好答案”,因为这个问题明确地要求ObjectiveC。随着苹果在WWDC14上引入Swift,我想分享一下在Swift中使用块(或闭包)的不同方式

你好,斯威夫特 您可以使用多种方法传递与Swift中的函数等效的块

我找到了三个

为了理解这一点,我建议您在操场上测试这段代码

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针对异步开发进行了优化,苹果在闭包方面做得更多。 第一个是可以推断函数签名,因此不必重写它

通过数字访问参数 带命名的参数推理 尾随闭合 这种特殊情况仅在块是最后一个参数时有效,称为尾随闭包

下面是一个示例(与推断的签名合并以显示迅捷的力量)

最后:

使用所有这些功能,我要做的是混合尾随闭包和类型推断(为可读性命名)


你好,斯威夫特

补充@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)

当然,您可以使用块作为属性。但要确保它们被声明为@property(copy)。例如:

typedef void(^TestBlock)(void);

@interface SecondViewController : UIViewController
@property (nonatomic, copy) TestBlock block;
@end

在MRC中,捕获上下文变量的块被分配到堆栈中;当堆栈帧被销毁时,它们将被释放。如果它们被复制,一个新的块将被分配到堆中,这可以在堆栈帧弹出后执行。

好吧,因为这会非常方便。我不需要知道它是什么,只要我有正确的语法,它的行为像一个NSObject。如果你不知道它是什么,你怎么知道它会很方便?如果你不知道它们是什么,你不应该使用它们:)@Moshe这里有一些原因浮现在脑海中。块比完整的委托类更容易实现,块是轻量级的,并且您可以访问该块上下文中的变量。使用块可以有效地进行事件回调(cocos2d几乎完全使用它们)。这并不完全相关,但由于一些评论抱怨“丑陋”的块语法,因此这里有一篇很棒的文章,它从第一原则推导出语法:对于xCode 4.4或更新版本,您不需要合成。这将使它更加简洁。哇,我不知道,谢谢。。。虽然我经常做合成myProp=\u myProp@Robert:你又运气好了,因为如果不把合成放进去,默认情况就是你正在做的事@CharlieMonroe-是的,你可能是对的,但是你不需要一个dealloc实现来nil或释放块属性而不使用ARC吗?(我已经有一段时间没有使用非ARC了)@imcaptor:是的,如果你不在dealloc中释放它,它可能会导致内存泄漏-就像其他变量一样。这个答案真的会给已经提供的其他答案增加什么吗?Alex,很好的关联示例。你知道吗,我想知道非原子。想法?对于一个财产来说,“原子”是正确的做法是非常罕见的。在一个线程中设置块属性,同时在另一个线程中读取它,或者在多个线程中同时设置块属性,这将是一件非常奇怪的事情。所以“原子”和“非原子”的成本并没有给你带来任何真正的优势。这是苹果公司的实际文件,说明你为什么要这么做
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)
let resultShortAnon = test({return "ANON_" + $0 + "__ANON" })
let resultShortAnon2 = test({myParam in return "ANON_" + myParam + "__ANON" })
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!")
    }
}
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)
typedef void(^TestBlock)(void);

@interface SecondViewController : UIViewController
@property (nonatomic, copy) TestBlock block;
@end