Chapter 23: Think Different: Blocks and Functional Programming

Programming paradigms fall into three major categories: procedural programming, object-oriented programming, and functional programming. Most modern programming languages—such as Java, C#, or Objective-C—don’t fall purely into a specific paradigm. They are usually inclined to one while including some methodologies from the others. Objective-C is primarily object-oriented, yet it borrows some functional aspects using blocks. This chapter is about the functional programming aspects in Objective-C.

The functional programming (FP) paradigm is easy to explain theoretically, but its highly abstract nature makes it hard to understand and realize its power. The easiest way to really comprehend and appreciate FP is to implement a practical system. Later in this chapter, you dirty your hands with a dash of FP by writing an FP equivalent of a commonly used Cocoa method, and then go deeper by writing a category addition that makes UIAlertView to use blocks. Finally, you learn about some of the block-based methods added to the Cocoa framework from iOS 4 onward. Now, it’s time to get started.

What Is a Block?

Simply defined, a block is an ad hoc piece of code. Just as you would with a primitive data type like an integer or double, you declare a block and start using it. You can pass blocks as parameters, “copy” them for use later, and do pretty much anything that you would normally do to a primitive data type. Veteran C programmers have been using function pointers to do pretty much what I just explained. What sets a block apart from a function pointer (which is different enough to be called a programming paradigm by itself) is that it can be declared within the lexical scope of another method, and that it can “capture the state” of the variables in that scope. This means that a block has contextual information without the programmer needing to do anything, unlike a function pointer.

A block differs from a function pointer by the way it is written and by its inherent nature to capture the state of local variables and optionally modify them.

Now, that paragraph doesn’t really help you to understand the concept. It is analogous to a chapter about object-oriented programming that says: An object is an “entity” that encapsulates code with data. You will be hesitant to use blocks and the functional programming paradigm if you don’t comprehend it conceptually. So, before I talk about another abstract point, let’s get this one straight by thinking outside the box. To do that, I’ll show you a practical, nonprogramming-related example.

Why Use Functional Programming?

To understand why you should use a functional programming paradigm, it might help to relate it to something outside of the programming world. I’m going to digress a bit here, but I promise it will take fewer than a couple of minutes of your reading time.

The Human Brain Versus the Microprocessor

A microprocessor stores data in an addressable fashion and executes instructions to process them. The human brain, on the other hand, thinks and stores data associatively. Here’s an example: On a microprocessor, you store a number, the value 10, and access it by its address 0x8BADF00D. When you ask the microprocessor about the location of the number, it returns the address. The human brain works differently. The answer to the question “Where is my iPhone?” would probably be similar to “It’s in the living room on top of the DVD player.” The human answer won’t even remotely be like “It’s 5.04 meters northeast at an angle 27.23 degrees from the main entrance to the living room.” Humans associate the location of the iPhone with the location of the DVD player and the location of the DVD player with the location of the living room. That’s a huge difference in the thought processes between how a microprocessor works and how a human brain works. This difference in thought process is akin to the difference between the procedural and functional programming paradigm.

Procedural Versus Functional Paradigm

Procedural programming is all about feeding your microprocessor with instructions. While that has worked very well for decades, some real-world programming tasks are easier to think about and express as abstract concepts than as a bunch of instructions. Let me give you an example. (No, not that clichéd Factorial example; read on, this is going to be Objective-C.)

A “Functional” UIAlertView

For this example, you want to show a UIAlertView and take an action when the user taps on the Affirmative button. The procedural way of doing this is to create a UIAlertView object, own its delegate and implement the callbacks, show the UIAlertView, and release it.

UIAlertView Example (The Procedural Way)

-(IBAction) buttonTapped:(id) sender  {

  UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@”Send email”

  message:@”Are you sure you want to send it now?”

  delegate:self

  cancelButtonTitle:@”Cancel”

  otherButtonTitles:@”Send”, nil];

  [alert show];

  [alert release];

}

-(void)alertView:(UIAlertView*) alertView didDismissWithButtonIndex:(NSInteger) buttonIndex  {

  

  if(buttonIndex != [alertView cancelButtonIndex])  {

    [self sendTheMail];

  }

}

-(void) sendTheMail  {

  // write actual code for sending the mail

}

Implementation (and syntax) aside, now look at how you call a UIAlertView that adheres to the functional paradigm.

UIAlertView Example (The Functional Way)

[UIAlertView showAlertViewWithTitle:@”Send email”

message:@”Are you sure you want to send it now?”

cancelButtonTitle:@”Cancel”

otherButtonTitles:[NSArray arrayWithObjects:@”Send”, nil] onCompletion:^{

  // write actual code for sending the mail

}

onCancel:^{

  // write code for handling other cases

}];

That’s much cleaner.

You don’t have to implement a delegate.

You don’t have to allocate or release objects.

You don’t have to explicitly show the alert.

Instead, you specify your intent and things happen behind the scenes automatically for you.

In the functional paradigm example, your code reads like English. You declaratively say what your title is, and what the message you need to show is. When the user closes the alert, you declaratively state the code to execute for both cases, closing by accepting the alert and closing by cancelling the alert instead of implementing a delegate.

The point is that instead of instructing, you specify your intent, and the code becomes much cleaner to read and follow.

You will appreciate this code when you show multiple alerts in a single view controller and use tags to differentiate the alert views on the callback delegate. If you understand this, you have grasped the essence of the functional programming paradigm.

You learn about implementing this method as a category addition to UIAlertView along with syntax and other associated matters in the “Block-Based UIAlertView” section later in this chapter.

Because microprocessors still execute instructions one by one, you may wonder why you should bother about functional programming. That’s a valid question. The functional paradigm is almost always for writing software that’s easy for co-developers to read and understand. In nearly every case, an equivalent imperative logic is less expensive to execute, but with Moore’s law, and the rate at which microprocessor speed increases, code clarity is often more important than writing efficient code. Again, that doesn’t always mean you should adhere to a functional paradigm. Not every real-world problem can be represented in a functional way.

I hope I’ve persuaded you to learn about and use the functional paradigm, so now it’s time to dive into the technical bits of it.

Declaring a Block

You declare a block using the ^ (caret) character.

int (^MyBlock) (int parameter1, double parameter2);

This syntax is for a block called MyBlock that takes an int and double as parameters and returns an integer. In most applications, you would typedef a block like this:

typedef int (^MyBlock) (int parameter1, double parameter2);

You can now declare instances of your block as you would declare any other data type.

MyBlock firstBlock, secondBlock;

You assign a block like this:

firstBlock = ^(int parameter1, double parameter2)  {

// your block code here

NSLog(@”%d, %f”, parameter1, parameter2);

}

Because the block takes in an integer and a double as parameters, you can invoke them like this:

firstBlock(5, 2.3);

Invoking this block in this case will NSLog the numbers to the console. That’s pretty much all for the syntax.

Scope of Variables

You learned earlier in this chapter that compared to a function pointer, a block has access to the variables in its lexical scope. Optionally, a block can modify a variable in the lexical scope even if the variable goes out of scope. To allow a block to access variables within a lexical scope, the Objective-C runtime allocates blocks on the stack.

When you’re passing a block as a parameter to other methods, you copy the block to the heap. This is because blocks, when used as parameters, will be invoked after the stack in which they were originally created is deallocated. You can use the normal Objective-C copy message to copy a block. This also copies/retains variables in the block’s lexical scope. This is a very important concept to understand when you use blocks in your code. In the next section, you read scenarios about when a variable is copied and when it is retained.

Warning: A block cannot be retained. Sending a retain message is a no-op and doesn’t increase the retain count. Normally, you wouldn’t send a retain message explicitly. But you should keep an eye on the storage semantics you use when you declare a block as a property. Even the omniscient LLVM compiler doesn’t warn you when you use retain as a storage type for a block property.

Stack Versus Heap

A block is a different kind of Objective-C object. Unlike traditional objects, blocks are not created on the heap. This is primarily for two reasons. The first is performance: A stack allocation is almost always faster than heap. The second reason is the necessity to access other local variables.

Now, a stack gets destroyed when the scope of the function ends. If your block is passed to a method that needs it even after its scope is destroyed, you should copy your block. This is where Objective-C runtime performs some magic behind the scenes. When a block is copied, it’s moved from stack to heap. Along with the block, the local variables defined in its scope are copied when you reference it within your block. All NSObject subclasses that are referenced are retained instead of copied (because they are already on heap, and retain is less time-consuming than a copy). The Objective-C runtime gives a const reference to every local variable to a block. This also means that a block cannot modify the contextual data by default, and code like the following will result in a compilation error.

int statusCode  = -1;

Myblock b = ^{

  statusCode = 4;

};

But I previously said that blocks could “optionally” modify the local variables. To allow modification, you declare variables with a __block modifier. So the declaration of statusCode is now __

block int statusCode = -1;

The reason for this additional modifier is to instruct the compiler to copy the __block variables when the block is copied. Copying is a more time-consuming operation than either retain or passing by a const reference, and the implementers decided to leave this in the hands of the developer.

__block variables are copied instead of being retained.

Now, coming back to the previous example of a blocks-based UIAlertView, your block has all contextual information available without declaring any additional data structures. Your UIAlertView onDismiss or onCancel block methods can access the local variables without the developer managing them (through context parameters).

However, it comes with a minor catch that you should be wary of: the retain cycle.

The Retain Cycle Problem

__block TWTweetComposeViewController *controller =

  [[TWTweetComposeViewController alloc] init];

        [controller setInitialText:@”Test Tweet”];

        

        controller.completionHandler =

         ^(TWTweetComposeViewControllerResult result)  {

            

            controller = nil; // retain cycle issue

            [self dismissModalViewControllerAnimated:YES];

        };

If you attempt to capture a variable within a block as shown in the preceding code, you end up with a retain cycle that never gets deallocated. With the new LLVM compiler, you normally don’t have to worry much about this because it’s clever enough to point out the issue.

Implementing a Block

Now that you know the workings of a block, let’s implement the UIAlertView block-based example I showed you in the previous section.

Block-Based UIAlertView

You want the syntax for this example to be like the following:

[UIAlertView showAlertViewWithTitle:(NSString*)title

message:(NSString*) message

cancelButtonTitle: (NSString*) cancelTitle

otherButtonTitles: (NSArrat*) otherButtons

onCompletion:^{

  // write actual code for sending the mail

}

onCancel:^{

  // write code for handling other cases

}];

Follow these steps to implement the UIAlertView block-based example:

1. Add a Category class on UIAlertView. You can use the Category template provided in Xcode 4.5. Call the Category class UIAlertView (Blocks).

2. typedef your Dismiss and Cancel blocks:

typedef void (^DismissBlock)(int buttonIndex);

typedef void (^CancelBlock)();

3. Add the method definition to the header file:

+ (UIAlertView*) showAlertViewWithTitle:(NSString*) title

                                message:(NSString*) message

                      cancelButtonTitle:(NSString*) cancelButtonTitle

                      otherButtonTitles:(NSArray*) otherButtons

                              onDismiss:(DismissBlock) dismissed

                               onCancel:(CancelBlock) cancelled;

4. Declare static storage for the blocks on the implementation:

static DismissBlock _dismissBlock;

static CancelBlock _cancelBlock;

5. Implement your block-based method:

+ (UIAlertView*) showAlertViewWithTitle:(NSString*) title

                                message:(NSString*) message

                      cancelButtonTitle:(NSString*) cancelButtonTitle

                      otherButtonTitles:(NSArray*) otherButtons

                              onDismiss:(DismissBlock) dismissed

                               onCancel:(CancelBlock) cancelled {

  

_cancelBlock  = [cancelled copy];

  

_dismissBlock  = [dismissed copy];

  

  UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title

                                                  message:message

                                                 delegate:[self self]

                                        cancelButtonTitle:cancelButtonTitle

                                        otherButtonTitles:nil];

  

  for(NSString *buttonTitle in otherButtons)

    [alert addButtonWithTitle:buttonTitle];

  

  [alert show];

  return alert;

}

Note that you have copied the block parameters passed to the method to the static storage. That’s because you have to invoke those block methods later in the UIAlertViewDelegate.

6. Handle the UIAlertViewDelegate:

+ (void)alertView:(UIAlertView*) alertView

   didDismissWithButtonIndex:(NSInteger) buttonIndex {

  

  if(buttonIndex == [alertView cancelButtonIndex])  {

    _cancelBlock();

  }

  else  {

    _dismissBlock(buttonIndex - 1);// cancel button is button 0

  }

  

}

The delegate method is nothing fancy. Just handle it and call the appropriate block method.

With about 50 lines of code, you implemented a block-based UIAlertView. This should help write clean, readable code on your view controllers. You can implement similar methods for UIActionSheet as well.

You can download the complete source code for the block-based UIAlertView from the book’s website.

This should give you a complete understanding of how to use blocks in a much more sophisticated example. That completes the example; in the next section, you learn about Cocoa functions that take blocks as parameters.

Blocks and Concurrency

By now, you know how to use blocks and should be comfortable with the syntax. Now I’ll talk about one other important benefit you get from blocks: concurrency.

Managing concurrency has always been the hardest part of programming. Blocks are an excellent use case here because they can be used for creating units of programming or tasks that can be executed independently. Blocks can be used with dispatch queues in Grand Central Dispatch (GCD) or NSOperationQueue without needing to create threads explicitly. Using an NSOperationQueue is something you have already done in the RESTEngine implementation.

In the next section, you briefly go through a feature of iOS and OS X called GCD and discover how blocks and dispatch queues in GCD work together to make concurrency implementation easier. Later on, I’ll compare GCD with NSOperationQueue and provide suggestions on when to use what.

Dispatch Queues in GCD

Grand Central Dispatch is a very powerful feature that allows you to write concurrent code easily. It shifts the burden of managing multiple threads and thread synchronization to the operating system (iOS or OS X). When you use GCD, you create units that can be executed independently of each other and let the operating system handle the queuing and synchronization for you. The GCD implementation on iOS (and OS X) consists of a set of C language extensions, APIs, and a runtime engine. GCD automatically ensures that your independent units are executed on multiple processors if available (like iPad 2). As a developer, the only thing you have to focus on is designing your heavy worker processes so that they work independently of each other (as opposed to threads with shared synchronized data). GCD also provides context pointers to share data across your blocks. You learn more about GCD in Chapter 13.

GCD provides three types of dispatch queues—serial, concurrent, and main—to which you can enqueue your task. The serial queue executes one task at a time in first-in-first-out (FIFO) order, and the concurrent queue executes them in parallel, also in FIFO order. The main dispatch queue executes operations on the main thread, which is usually used to synchronize execution across threads executing in different serial/concurrent queues. Now, you’ll see how to create a dispatch queue and submit tasks to it.

Creating a dispatch queue is as easy as one C function call:

myQueue = dispatch_queue_create(“com.mycompany.myapp.myfirstqueue”, NULL);

To dispatch tasks asynchronously to this queue, use the dispatch_async method. That method takes your block as the second parameter. It essentially queues your block to the queue specified in the first parameter. This is yet another few lines of code:

dispatch_async(myQueue, ^(void) {

  [self doHeavyWork];

});

That’s it. Without explicitly using a thread and in less than ten lines of code, you have implemented GCD in your app! Designing your blocks in an independent way already solved most of the complexities involved around synchronization. For example, in the preceding code, the doHeavyWork method is designed to work independently with its own data.

Imagine that the doHeavyWork method is an image manipulation method. To design it so that it runs independently, slice the image (vertically or horizontally), pass each slice to a block, and send this to a dispatch queue instead of using the complete image data on a shared synchronized variable. That is, if you have a 3200 × 2000-pixels image and you want to apply a filter on it, slice it to 10 different images of 320 × 2000 pixels each and process them independently. After processing is done, stitch them back together on the main dispatch queue and notify the relevant observers.

NSOperationQueue Versus GCD Dispatch Queue

You already know that iOS provides another queuing mechanism called NSOperationQueue. This also takes blocks as parameters and queues them just like a dispatch queue. Now, you might have a question: When should I use GCD and when should I use NSOperationQueue?

Here are some similarities and differences between NSOperationQueue and GCD:

NSOperationQueue is built using GCD and is a higher-level abstraction of it.

GCD supports only FIFO queues, whereas operations queued to an NSOperationQueue can be reordered (reprioritized).

Setting dependencies between operations is possible with NSOperationQueue but not with GCD. If one of your operations needs data that is generated by the other, you can set the operation to be dependent on the other operation, and NSOperationQueue automatically executes them in the correct order. With GCD, there is no built-in support to set dependencies.

NSOperationQueue is KVO-compliant. This means you can observe the state of the tasks. Does that mean you should always use NSOperationQueue instead of GCD? The answer is no. NSOperationQueue is slower than GCD in terms of execution speeds. If you profile your code using Instruments and you think you need more performance, use GCD. Usually in lower-level code, you may not have task dependencies or a necessity to observe state using KVO. As always, follow Donald Knuth’s quote, “We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil,” and use the lower-level GCD only if it improves performance gains when profiled with Instruments.

Block-Based Cocoa Methods

With iOS 4 and the introduction of blocks, many of the built-in Cocoa framework methods have block-based equivalents. Covering every single block-based method is impossible in a single chapter and merits a complete book of its own. But Apple follows a pattern. In this section, I briefly explain some of the methods that take block parameters and give some hints and tips on when to look out for a block-based equivalent method in the framework.

UIView Animations Using Blocks

Prior to iOS 4, view-based animations were usually done using UIView’s class methods, beginAnimations and commitAnimations. You write the code you want to be animated within these two statements, and the animation is performed after the call to commitAnimations.

Code to animate the alpha value of a view will look something like the following.

Animation in iOS 3 (Without Blocks)

[UIView beginAnimations:@”com.mycompany.myapp.animation1”

  context:&myContext];

[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];

[UIView setAnimationDuration:1.0f];

[UIView setAnimationDelay:1.0f]; // start after 1 second

[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:)];

  self.imageView.alpha = 0.0;

[UIView commitAnimations];

Starting with iOS 4, UIView has several equivalent block-based animation methods. One method that you’ll quite commonly use is animateWithDuration:delay:options:animations:completion:. The previous code snippet can be expressed using this method as follows.

Animation in iOS 4 and Above (with Blocks)

[UIView animateWithDuration:1.0 delay:1.0

options:UIViewAnimationCurveEaseInOut

                     animations:^ {

                         self.imageView.alpha = 0.0;

                     }

                     completion:^(BOOL finished) {

                         [self. imageView removeFromSuperView];

                     }];

Note that the blocks version also removes the imageView after animation is complete, something that is done on the callback method animationDidStop:animated: in the iOS 3 version (not illustrated). Other block-based animation methods are permutations of this method, omitting parameters like delay, options, and completion block. A huge advantage of this method is that you don’t have to maintain context you normally set with the methods setAnimationWillStartSelector: and setAnimationDidStopSelector:. Because a block is aware of the local context, you don’t even need a context parameter.

Presenting and Dismissing View Controllers

iOS 5 introduced a new method for presenting and dismissing view controllers that takes a block parameter that must be called when the presenting (or dismissing) animation is completed. This block parameter is called after viewDidDisappear is called. Prior to iOS 5, you might have done some cleanup code in viewDidDisappear. With this method in iOS 5, you can easily do that in the completion block. The methods can be invoked like this.

Presenting

[self presentViewController:myViewController animated:YES completion:^  {

  //Add code that should be executed after view is presented

        }];

Dismissing

[self dismissViewControllerAnimated:YES completion:^  {

  //Add code that should be executed after view is presented

}];

TweetComposer Versus In App E-mail/SMS

In iOS 5, Apple added native support for Twitter, and apps that need to send out a tweet could just instantiate a TWTweetComposerViewController, prepopulated with the text to be tweeted, and present it to the user. The implementation is very similar to how you normally send an in app e-mail or SMS. However, the TWTweetComposeViewController reports completion by a block parameter instead of a delegate. Your completion handler will look something like the following code.

TwTweetComposeViewController Completion Handler

controller.completionHandler = ^(TWTweetComposeViewControllerResult result)

  {

            [self dismissModalViewControllerAnimated:YES];

            switch (result) {

                case TWTweetComposeViewControllerResultCancelled:

                    break;

                case TWTweetComposeViewControllerResultDone:

                    break;

            }

        };

Dictionary Enumeration Using NSDictionary enumerateWithBlock

Dictionary enumeration using block-based methods is sure to make your code cleaner. You no longer have to deal with keyEnumerator or objectForKey methods. With block-based equivalents, it’s much easier, as shown here:

    [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id val, BOOL

      *stop)  {

        

        //NSLog(@”%@, %@”, key, val);

    }];

Looking for Block-Based Methods

The Cocoa framework follows a pattern when using blocks. Here are a few patterns that can help you in searching for equivalent block-based methods in the Cocoa framework:

Check whether the current method has a context parameter for a Cocoa method. If it does, then the chances are that there will be a block-based equivalent.

Look for delegates with one or two optional methods. You might find a completionHandler for classes that were previously notifying results via delegates.

Enumeration, sorting, and filtering methods mostly have block equivalents. Examples include, NSArray, NSDictionary, NSString, NSAttributedString, NSFileManager, and several others.

Once you get used to the Cocoa framework design pattern and functional programming paradigm, you should be able to intuitively guess whether a method might have an equivalent block-based method.

Supported Platforms

Blocks are supported from iOS 4 and Snow Leopard. This means that when you use blocks, you should raise your minimum deployment target to iOS 4.0 for iOS projects and Mac OS X 10.6 for Mac projects. In 2012–2013, you shouldn’t be worrying about this as almost all devices run iOS 4 and above so nothing should stop you from using blocks. When you are writing an iOS app that has a Mac counterpart and you are sharing the code across platforms, remember that Leopard and prior operating systems don’t support blocks natively. But there is a third-party open-source block-based runtime called PLBlocks (see the “Further Reading” section at the end of this chapter) that allows support for blocks on those operating systems. For Mac projects, my recommendation is to start using Apple’s equivalent block-based Cocoa methods using conditional compilation and then remove it altogether when Snow Leopard/Lion/Mountain Lion usage is high enough, which I predict isn’t more than a year away.

Summary

This chapter discussed the functional paradigm, a very powerful paradigm that can make your code more readable (as in case of the UIAlertView example) and help you write less code. Functional programming will be the next big programming paradigm change after object-oriented programming, and you’ll be seeing more and more Cocoa methods using and accepting blocks.

Apple usually makes older technologies obsolete faster than its competitors. As much as this is true for the products it makes, it’s also true for the Apple API. The TWTweetComposeViewController class is a perfect example of this. While it is similar to the MFMailComposeViewController class, handling responses from TWTweetComposeViewController is via a completionHandler block, unlike MFMailComposeViewController that uses a MFMailComposeViewControllerDelegate. Note that TWTweetComposeViewController doesn’t even support delegates.

On similar lines, for maybe another couple of years, there will be block-based additions to existing methods, but newer classes will have only block-based parameters, and you’ll eventually be forced to use them. A paradigm change like this is tough. But the sooner you get accustomed to the changes, the better.

Further Reading

Apple Documentation

The following documents are available in the iOS Developer Library at developer.apple.com or through the Xcode Documentation and API Reference.

iOS Programming Guide. “Blocks Programming Topics”

Concurrency Programming Guide. “Migrating Away from Threads—Apple Developer”

Blogs

mikeash.com. “Friday Q&A 2009-08-14: Practical Blocks”http://www.mikeash.com/pyblog/friday-qa-2009-08-14-practical-blocks.html

Cocoa with Love. “How blocks are implemented (and the consequences)”http://cocoawithlove.com/2009/10/how-blocks-are-implemented-and.html

JCMultimedia. How to make iPhone Apps and Influence People. “Is it worth supporting iOS 3 devices?”http://blog.jcmultimedia.com.au/2011/03/is-it-worth-supporting-ios-3-in-2011.html

“Plblocks: Block-capable Toolchain: Runtime for Mac OS X 10.5 and iPhone OS 2.2+”http://code.google.com/p/plblocks/

Eschatology. “When to use NSOperation vs. GCD”http://eschatologist.net/blog/?p=232

Other Resources

MugunthKumar / UIKitCategoryAdditionshttps://github.com/MugunthKumar/UIKitCategoryAdditions

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.60.158