Absolute Ripple
  • Absolute Ripple
  • Contact

Block Based Completion Handler

11/8/2013

0 Comments

 
If you have used some of iOS methods that uses block you would probably agree that they are quite wonderful to use. I am talking about methods such as these:
[UIView animateWithDuration:5.0
                     animations:^{
                         // some code
                     } completion:^(BOOL finished) {
                         // some code
                     }];

[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        // some code
    }];

Blocks enable you to write more compact and flexible codes that can be easily reused in your programs. It does take awhile to get use to the most weird looking syntax though.

Then you start to think, wouldn't it be nice if I could use a block based completion handler in some of my methods. But how? It looks so confusing and you just don't know where to begin. The block syntax makes it appears harder than it really is. The basic pattern is simple.

The Pattern

1. Typedef the block
typedef void (^NameOfYourCompletionHandler)(NSString *name, BOOL finished);
This block calls 'NameOfYourCompletionHandler'. It has two arguments - an NSString and a BOOL. Obviously, you can have more or less arguments to suit your situation.

2. Add a property
@property (nonatomic, copy) NameOfYourCompletionHandler nameOfYourCompletionHandler;
This is just like how you define any other property. i.e. preceding the name of the property with the type (i.e. NameOfYourCompletionHandler here). The name of the property can be whatever you like. If the code uses only one property of this block type, it is generally preferable to keep the property name the same as the name of the type (and lower casing the first character) to make it easier to follow.

3. Create an instance method (not a class method) that takes the block as one of its argument
- (void)doSomeTask:(NSString *)taskName withCompletion:(NameOfYourCompletionHandler)completionBlock
{
    self.nameOfYourCompletionHandler = completionBlock;
    // code to do something
}
The line self.nameOfYourCompletionHandler = completionBlock is important as this copies the completionBlock code to the instance variable so that it can be invoked later.
As noted above, this cannot be a class method as a class method would have any instance variables, such as the nameOfYourCompletionHandler here. If you must use a class method, you need to use static storage instead.

4. Call the completion block when you want to invoke it.
self.nameOfYourCompletionHandler(@"some name", YES);
This simply calls the completion block code and passes in the arguments.

This is all you need. And you can use the block based instance method like this, assuming you are invoking it within the same class:
[self doSomeTask:@"some task name" withCompletion:^(NSString *name, BOOL finished) {
        // code you want to perform
        // i.e. code you want to execute when the completion block is invoked under (4) above.    
    }];

       
Looking around online you will come across slight variation to the above, but the underlying pattern is the same. Some don't use typedef, and some don't use property (using static storage instead).

Without Typedef
Without using typedef, (2) would look like:
@property (nonatomic, copy) void (^nameOfYourCompletionHandler)(NSString *, BOOL)

And (3) would look like:
- (void)doSomeTask:(NSString *)taskName withCompletion:(void(^)(NSString *name, BOOL finished))completionBlock
{
    self.nameOfYourCompletionHandler = completionBlock;
    // code to do something
}

The rest would be the same.

Typedef makes the code looks cleaner (i.e. less weird syntax). However, it is just a personal preference/ coding style thing.

Using Static Storage
If you want to use block with class method you can do so with static storage.
Instead of (2), you would declare the static storage as follows in your implementation file:
static NameOfYourCompletionHandler _nameOfYourCompletionHandler;
And (3), would look like:
+ (SomeClass*)doSomeTask:(NSString *)taskName withCompletion:(NameOfYourCompletionHandler)completionBlock
{
   
_nameOfYourCompletionHandler = [completionBlock copy];
    // code to do something
}

And (4) becomes:
_nameOfYourCompletionHandler(@"some name", YES);

Other Useful Reference About Using Block
- Working with Blocks
- Using Blocks in iOS 4: The Basics
0 Comments

Your comment will be posted after it is approved.


Leave a Reply.

    Archives

    August 2013
    July 2013
    June 2013
    May 2013
    January 2013
    October 2012
    September 2012
    March 2012
    February 2012

    Categories

    All
    Apple Policy
    In App Purchase
    Ios Programming
    Our Apps

    RSS Feed

    Disclaimers

    Here are some resources that I find useful in writing iOS apps. These are not necessarily unique as they are based on various sources online.
    This is mainly to provide a source of reference to myself and my associates but if it can be of use to someone else, that is good.
    Note that information is provided here as is. Use at your own risk. There is no guarantee that it is accurate. We will update the information as time and resources permit.

    Powered by Create your own unique website with customizable templates.