Categories
automatic-ref-counting ios objective-c objective-c-blocks

Can I use Objective-C blocks as properties?

327

Is it possible to have blocks as properties using the standard property syntax?

Are there any changes for ARC?

8

  • 1

    Well, because it would be very in handy. I wouldn’t need to know what it is as long as I have the syntax right and it behaves like an NSObject.

    – gurghet

    Oct 14, 2010 at 17:09


  • 5

    If you don’t know what it is, how do you know that it would be very handy?

    Oct 14, 2010 at 17:14

  • 5

    You shouldn’t use them If you dont know what they are 🙂

    Oct 14, 2010 at 18:30

  • 5

    @Moshe here are some reasons that come to mind. Blocks are easier to implement than a full delegate class, blocks are lightweight, and you have access to variables that are in the context of that block. Event Callbacks can be done effectively using blocks (cocos2d uses them almost exclusively).

    Feb 3, 2012 at 21:40

  • 3

    Not completely related, but since some of the comments complain about “ugly” block syntax, here is a great article that derives the syntax from first principles: nilsou.com/blog/2013/08/21/objective-c-blocks-syntax

    Sep 24, 2013 at 16:28

315

@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

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

19

  • 3

    With xCode 4.4 or newer you dont need to synthesize. That will make it even more concise. Apple Doc

    – Eric

    Nov 8, 2012 at 4:28


  • wow, I didn’t know that, thanks! … Although I often do @synthesize myProp = _myProp

    – Robert

    Nov 8, 2012 at 8:04


  • 8

    @Robert: You are in luck again, because without putting @synthesize the default is what you are doing @synthesize name = _name; stackoverflow.com/a/12119360/1052616

    – Eric

    Nov 12, 2012 at 3:58


  • 1

    @CharlieMonroe – Yes you are probably right, but dont you need a dealloc implementation to nil or release the block property without ARC? (its been a while since I used non-ARC)

    – Robert

    Mar 31, 2013 at 21:58

  • 1

    @imcaptor: Yes, it can cause memory leaks in case you don’t release it in dealloc – just like with any other variable.

    Jun 15, 2013 at 8:59

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:

^ (id obj1, id obj2)
{
    return rand();
};

I hope this helps.

EDIT March 12, 2012:

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.

For more reading, please check out this document:
http://clang.llvm.org/docs/AutomaticReferenceCounting.html

0

    161

    @property (copy)void

    @property (copy)void (^doStuff)(void);
    

    It’s that simple.

    Here is the actual Apple documentation, which states precisely what to use:

    Apple doco.

    Your .h file:

    // 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".
    

    Your .m file:

     -(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.

    3

    • Maybe you should also say, that now ( 2016 ) it’s ok to use strong instead of copy?

      – Nike Kov

      Oct 11, 2016 at 14:44

    • Can you explain why the property shouldn’t be nonatomic unlike best practices for most other cases using properties?

      Nov 15, 2016 at 22:30

    • 1

      WorkingwithBlocks.html from Apple “You should specify copy as the property attribute, because…”

      – Fattie

      Nov 15, 2016 at 22:43