Blocks help you write better code in a number of ways. Here are two.
More Reliable Code
One advantage is more reliable code. Here's a specific example.
Prior to iOS 4.0, to animate views, you had to use the beginAnimations:context:
and commitAnimations
messages, like this:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelay:1.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
self.basketTop.frame = basketTopFrame;
self.basketBottom.frame = basketBottomFrame;
[UIView commitAnimations];
Note that you have to remember to put in the call to commitAnimations
, or your app will misbehave. The compiler will not warn you that you forgot to call commitAnimations
.
In iOS 4.0, Apple added blocks, and they added new ways to animate your views using blocks. For example:
[UIView animateWithDuration:0.5 delay:1 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.basketTop.frame = basketTopFrame;
self.basketBottom.frame = basketBottomFrame;
} completion:nil];
The advantage here is that there's no possibility of forgetting to commit the animation. The compiler will give you a syntax error if you forget to put }
at the end of the block or ]
at the end of the method. And Xcode will autocomplete the message name, so you don't have to remember how it's spelled.
Better Code Organization
Another advantage is better code organization. Here's an example.
Suppose you want to send a UIImage
to a server. Converting the image to PNG data might take some time, so you don't want to block the main thread while doing it. You want to do it in the background, on another thread. Prior to iOS 4.0, you might decide to use an NSOperationQueue
. First, you need to make a subclass of NSOperation
to do the work1:
@interface SendImageToServerOperation : NSOperation
@property (nonatomic, retain) UIImage *image;
@property (nonatomic, retain) NSURL *serverURL;
@end
@implementation SendImageToServerOperation
- (void)main {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:self.serverURL];
request.HTTPBody =UIImagePNGRepresentation(self.image);
NSURLResponse *response;
NSError *error;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
// Handle response/error here?
}
@end
Then, to actually do it, you need to create an operation and put it on a queue:
- (void)sendImage:(UIImage *)image toServerURL:(NSURL *)serverURL {
SendImageToServerOperation *operation = [SendImageToServerOperation new];
operation.image = image;
operation.serverURL = serverURL;
[backgroundQueue addOperation:operation];
}
The code is spread out. Starting in iOS 4.0, you can use blocks (and the new GCD framework2) to put it all together:
- (void)sendImage:(UIImage *)image toServerURL:(NSURL *)serverURL {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:serverURL];
request.HTTPBody =UIImagePNGRepresentation(image);
NSURLResponse *response;
NSError *error;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
// Handle response/error here?
});
}
You don't have to make a new class or even a separate function. You don't even have to create any extra objects. You can put the code where it's easiest to understand and maintain.
Footnote 1. This is not necessarily the best way to upload the data to the server. I chose a simple way for educational purposes. However, it is realistic to want to create the PNG data on a background thread.
Footnote 2. The NSBlockOperation
class (starting in iOS 4.0) lets you use blocks directly with NSOperationQueue
, if you prefer that over GCD.