For the More Curious: Pros and Cons of Callback Options

A callback, as you may remember from Chapter 4, is a chunk of code you supply in advance of an event occurring. When that event goes down, the chunk of code gets executed. While blocks have many more uses, you have seen in this chapter that they can be used as another approach to callbacks. Other approaches to callbacks you have seen are delegation, target-action pairs, and notifications. Each one has benefits and drawbacks compared to the others. This section will expand on these benefits and drawbacks so that you can pick the appropriate one for your own implementations.

First, let’s note that each of these approaches to callbacks are design patterns that transcend their implementations in Cocoa Touch. For example, the target-action pair design pattern is implemented by UIControl, but this does not mean you have to use UIControl to use the design pattern. You could create your own class that kept a pointer to a target object and a SEL for the message that object would be sent when some event occurred.

Callbacks have two major components: the process of registering it and the code for the callback. When registering a callback using delegation, target-actions or notifications, you register a pointer to an object. This is the object that will receive messages when events occur. Additionally, both target-actions and notifications require a SEL that will be the message that is sent to the object. Delegation, on the other hand, uses pre-defined methods from a delegate protocol to decide the messages that get sent.

Figure 24.4  Callback design patterns

Callback design patterns

In these three callback design patterns, the code for the callback is in a distinct method implementation. Overall, each of these approaches is pretty similar, but there are certain situations that work better when using one or the other.

You use target-action when you have a close relationship between the two objects (like a view controller and one of its views) and when there may be many instances of object that call back. For example, a single interface controlled by one controller may have many buttons. If those buttons only knew how to send one message (e.g., buttonTapped:), there would be mass confusion in the implementation of that method (Uhhh... which button are you again?).

Delegation is used when an object receives many events and it wants the same object to handle each of those events. You’ve seen many examples of this throughout this book, because delegation is a very common design pattern in Cocoa Touch. Because delegation uses a protocol that defines all of the messages that will be sent, you do not have control over the names of these methods, but you do not have to register them individually like with target-action pairs.

Notifications are used when you want multiple objects to invoke their callback for the same event and/or when two objects are not related. Consider an application that had two view controllers that were in a tab bar controller together. They don’t have pointers to each other, not like two view controllers in a navigation controller stack, but one of them is interested in what is going on in the other. Instead of giving them pointers to each other, which can be messy for a variety of reasons, one of view controllers can be kind and post notifications to the notification center. The other could register as an observer for that type of notification. Similarly, another view controller could come along and register for the same notification, and both observers would be updated.

Blocks are the outliers when it comes to callbacks because they are not an object-oriented approach. Blocks are useful when the callback is going to happen only once or when the callback is just a quick and simple task (like updating a progress bar). For example, in this chapter, you supplied a block for the completion of an animation. This animation was only going to run once, and therefore the block would only be called once.

One of the reasons blocks are better suited for this one-shot behavior is because they will retain any objects they reference. If a block was to stay around forever, the objects it references would also stay around forever. Of course, you can destroy the block when it is no longer needed, but what if that block is owned by an object that the block references? The object retains the block, the block retains the object, and now you can’t deallocate them without some extra work. Since the blocks stick around just for the one event, they will retain what they need until they no longer need it.

Another reason blocks are well-suited for this situation goes along with the reason why they are good for quick and simple tasks: you can define the block’s code at the same point where the block is registered as a callback. This keeps your code nice and clean.

An approach to callbacks we have not discussed is subclassing. In some languages, delegation is not feasible because of the structure of the language. In these languages, classes like CLLocationManager would be abstract classes – ones that were meant to be subclassed. Any time you wanted to use an instance of CLLocationManager, you would subclass it and write the code for what happens when an event occurs in the implementation of this subclass. The subclass would probably have an instance variable for the object it was going to tell about these events, and that object would declare and define these methods. This gets ugly pretty quickly, and thus, in Cocoa Touch, you do not see this pattern because we have better alternatives.

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

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