Saturday, July 17, 2010

Blocks in Objective-C

Unfortunately, Objective-C is dominated mostly by geniuses (who laugh at any possible ambiguity between "heap" and "stack") and newbies to programming ("I have an IBOutlet, but the screen is blank!?"). Thanks to iPhone development, there are increasing numbers of simple HelloWorld types of examples of things, but...

Block Basics

I'm not going to talk about whether the variables are on the heap or stack (which apparently is not that important in Obj-C, and many C developers misunderstand it anyway), nor about the problems with retain counts and other technical details about blocks. This topic is best covered by people who can really take it apart... maybe. Maybe I'll get to it myself. In any case, here's the definitive source.

But here are some examples for the lost. The syntax really really really sucks (compared to Ruby blocks, which are beautiful, but I digress). 

Simplest Example (void in, void out) of Passing a Block to a Function

typedef void (^simplestBlock)(void);

@synthesize window;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
simplestBlock b = ^(void) { NSLog(@"inside simple block"); };
[self blah:b];
}

- (void)blah:(simplestBlock)b {
b();
}

@end

Simplest Example, NSString* in

typedef void (^simplestBlock)(NSString *);

@synthesize window;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
simplestBlock b = ^(NSString* thing) { NSLog(@"got your string %@", thing); };
[self blah:b];
}

- (void)blah:(simplestBlock)b {
b(@"got one");
}

@end

Simplest Example, NSString* in and out

typedef NSString* (^simplestBlock)(NSString *);

@synthesize window;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
simplestBlock b = ^NSString* (NSString* thing) { return [NSString stringWithFormat:@"processed: %@", thing]; };
[self blah:b];
}

- (void)blah:(simplestBlock)b {
NSLog(@"here goes nothing: %@", b(@"stirng sent to block"));
}

@end

Simplest Example In and Out, No typedef

The typedef is recommended by Apple: "You can also create types for blocks—doing so is generally considered to be best practice when you use a block with a given signature in multiple places:" But what does it look like without them?


@synthesize window;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSString* (^b) (NSString *) = ^NSString* (NSString* thing) { return [NSString stringWithFormat:@"processed: %@", thing]; };
[self blah:b];
}

- (void)blah:(NSString* (^)(NSString* thing))b {
NSLog(@"here goes nothing: %@", b(@"stirng sent to block"));
}

@end

I cannot seem to increase the retain count of the block, so perhaps you don't need to release it?

Later: You don't need to release it nor retain it. However, under ARC you should always use copy if you're going to store it.



1 comment:

Dan Rosenstark said...

Damn this syntax is funny. Here's the missing case:


typedef id (^blockWithNoParametersAndIdReturn)(void);


blockWithNoParametersAndIdReturn b = ^id (void) { return nil; };