views:

94

answers:

2

Hi there,

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.

Thanks!

+3  A: 

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
Thanks so much Dave!
Jacob Relkin
@Dave is there a way to have a generic type for a block? I hate that i need to have a `typedef` there.
Jacob Relkin
@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
@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
+1  A: 

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
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
Very good point, Dave.
Barry Wark