45

I was wondering if it's possible to store a reference to an anonymous function (block) as an instance variable in Objective-C.

I know how to use delegation, target-action, etc. I am not talking about this.

Jacob Relkin
  • 161,348
  • 33
  • 346
  • 320

2 Answers2

87

Sure.

typedef void(^MyCustomBlockType)(void);

@interface MyCustomObject {
  MyCustomBlockType block;
}
@property (nonatomic, copy) MyCustomBlockType block; //note: this has to be copy, not retain
- (void) executeBlock;
@end

@implementation MyCustomObject
@synthesize block;

- (void) executeBlock {
  if (block != nil) {
    block();
  }
}

- (void) dealloc {
  [block release];
  [super dealloc];
}
@end

//elsewhere:

MyCustomObject * object = [[MyCustomObject alloc] init];
[object setBlock:^{
  NSLog(@"hello, world!");
}];

[object executeBlock];
[object release];
Dave DeLong
  • 242,470
  • 58
  • 448
  • 498
  • is there a way to have a generic type for a block? I hate that i need to have a `typedef` there. – Jacob Relkin Jul 12 '10 at 17:00
  • 3
    @Jacob yeah, you can do: `void(^)(void)` (or whatever block signature you need) anywhere you see `MyCustomBlockType`. However, I *promise* that using the `typedef` will make things much easier to grok in the long run. However, there's no way to say "any block with any return value and any parameters. You must be explicit about the signature. – Dave DeLong Jul 12 '10 at 17:48
  • 3
    @Jacob You're still limited by C's type system. There is no such thing as a "generic" block, though in C++ you might be able to do some pretty mind-bending things with templates and blocks. More realistically, type `id` is generic with respect to Objective-C types, so taking and returning (possibly nil) `id`'s gives you a lot of flexibility. – Barry Wark Jul 12 '10 at 18:11
  • 1
    Why copy, not strong? Even if I'm using ARC? – ma11hew28 Jan 08 '12 at 20:43
  • 1
    @MattDiPasquale "answered **Jul 12 '10 at 16:46**" means this answer pre-dates ARC ;) – Dave DeLong Jan 08 '12 at 20:45
  • Why the release after the call to `executeBlock`? You'd only want to do that if you were absolutely sure you wouldn't be calling it again, no? Or is that call necessary to release the captured variables in the stack block? – Brent Dillingham Jan 09 '12 at 18:19
  • @BrentDillingham the point was to illustrate how to have a block as an ivar. The allocation, execution, and immediate release of a helper object are just to provide some context of how one might use this. – Dave DeLong Jan 09 '12 at 19:49
  • @DaveDeLong Thanks - I realize now I mistakenly thought you were releasing the block itself as opposed to the object. As usual I read too quickly. – Brent Dillingham Feb 28 '12 at 02:29
  • 2
    Just to answer the EXPLICIT question asked by Jacob: @property (nonatomic, copy) void (^userObject)(); – David H May 04 '12 at 11:35
12

Yes, you most certainly can store a reference to a (copy) of an Objective-C block. The variable declaration is a little bit hairy, like C function pointers, but beyond that it's no problem. For a block that takes and id and returns void:

typedef void (^MyActionBlockType)(id);

@interface MyClass : NSObject 
{

}

@property (readwrite,nonatomic,copy) MyActionBlockType myActionBlock;
@end

will do the trick.

Barry Wark
  • 107,306
  • 24
  • 181
  • 206
  • 3
    The definition is definitely hairy. I *much* prefer using `typedef` to simply if. Then you can do insane things "blocks that accept a block as a parameter and return a block" and not get lost in the parenthesis. :) – Dave DeLong Jul 12 '10 at 16:49
  • is this `typedef void (^MyActionBlockType)(id);` correct? shouldn't it be `typedef void (^MyActionBlockType)(id obj);` – Duck Mar 25 '14 at 17:35
  • @RubberDuck, the name of the variable (obj) is irrelevant to the type, thus you don't need to declare it in typedef. The name is only relevant when you implement the block; – Teemu Kurppa Mar 30 '14 at 08:34