Delegation

When you set the delegate property of the CLLocationManager and implemented the two methods in WhereamiAppDelegate, you were using a design pattern called delegation. This is a very common pattern in Cocoa Touch, and many classes have a delegate property.

Delegation is an object-oriented approach to callbacks. A callback is a function that is supplied in advance of an event and is called every time the event occurs. Some objects need to make a callback for more than one event. For instance, the location manager wants to callback when it finds a new location and when it encounters an error.

However, there is no built-in way for two (or more) callback functions to coordinate and share information. This is the problem addressed by delegation – we supply a single delegate to receive all of the event messages for a particular object. This delegate object can then store, manipulate, act on, and relay the related information as it sees fit.

Let’s take a moment to compare delegation with another object-oriented approach to callbacks: target-action pairs. (You used this approach in Chapter 1 with the UIButtons in your Quiz application.) In a target-action pair, you have a target object that you send an action message to when an event occurs. The target must implement the action message, and, for each event, a new target-action pair must be created. With delegation, on the other hand, you set the delegate once and can then send it messages for different events. The delegate will implement the method for each event it wants to hear about (Figure 4.5).

Figure 4.5  Target-Action vs. Delegation

Target-Action vs. Delegation

Also, with a target-action pair, you can send the target any action message you choose. Delegation, however, does not offer this flexibility; an object can only send its delegate a specific set of messages listed in a protocol.

Protocols

For every object that can have a delegate, there is a corresponding protocol that declares the messages that the object can send its delegate. The delegate implements methods from the protocol for events it is interested in. When a class implements methods from a protocol, it is said to conform to the protocol.

The protocol for CLLocationManager’s delegate looks like this:

/​/​ ​N​o​t​e​ ​t​h​a​t​ ​a​ ​f​e​w​ ​m​e​t​h​o​d​s​ ​h​a​v​e​ ​b​e​e​n​ ​o​m​i​t​t​e​d​
/​/​ ​f​r​o​m​ ​t​h​e​ ​r​e​a​l​ ​d​e​c​l​a​r​a​t​i​o​n​ ​o​f​ ​t​h​i​s​ ​p​r​o​t​o​c​o​l​
/​/​ ​s​o​ ​w​e​ ​c​a​n​ ​f​o​c​u​s​ ​o​n​ ​w​h​a​t​ ​i​s​ ​g​o​i​n​g​ ​o​n​
@​p​r​o​t​o​c​o​l​ ​C​L​L​o​c​a​t​i​o​n​M​a​n​a​g​e​r​D​e​l​e​g​a​t​e​ ​<​N​S​O​b​j​e​c​t​>​

@​o​p​t​i​o​n​a​l​

-​ ​(​v​o​i​d​)​l​o​c​a​t​i​o​n​M​a​n​a​g​e​r​:​(​C​L​L​o​c​a​t​i​o​n​M​a​n​a​g​e​r​ ​*​)​m​a​n​a​g​e​r​
 ​ ​ ​ ​d​i​d​U​p​d​a​t​e​T​o​L​o​c​a​t​i​o​n​:​(​C​L​L​o​c​a​t​i​o​n​ ​*​)​n​e​w​L​o​c​a​t​i​o​n​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​f​r​o​m​L​o​c​a​t​i​o​n​:​(​C​L​L​o​c​a​t​i​o​n​ ​*​)​o​l​d​L​o​c​a​t​i​o​n​;​

-​ ​(​v​o​i​d​)​l​o​c​a​t​i​o​n​M​a​n​a​g​e​r​:​(​C​L​L​o​c​a​t​i​o​n​M​a​n​a​g​e​r​ ​*​)​m​a​n​a​g​e​r​
 ​ ​ ​ ​ ​ ​ ​d​i​d​U​p​d​a​t​e​H​e​a​d​i​n​g​:​(​C​L​H​e​a​d​i​n​g​ ​*​)​n​e​w​H​e​a​d​i​n​g​;​

-​ ​(​B​O​O​L​)​l​o​c​a​t​i​o​n​M​a​n​a​g​e​r​S​h​o​u​l​d​D​i​s​p​l​a​y​H​e​a​d​i​n​g​C​a​l​i​b​r​a​t​i​o​n​:​(​C​L​L​o​c​a​t​i​o​n​M​a​n​a​g​e​r​ ​*​)​m​a​n​a​g​e​r​;​

-​ ​(​v​o​i​d​)​l​o​c​a​t​i​o​n​M​a​n​a​g​e​r​:​(​C​L​L​o​c​a​t​i​o​n​M​a​n​a​g​e​r​ ​*​)​m​a​n​a​g​e​r​
 ​ ​ ​ ​ ​ ​ ​ ​ ​d​i​d​E​n​t​e​r​R​e​g​i​o​n​:​(​C​L​R​e​g​i​o​n​ ​*​)​r​e​g​i​o​n​;​

-​ ​(​v​o​i​d​)​l​o​c​a​t​i​o​n​M​a​n​a​g​e​r​:​(​C​L​L​o​c​a​t​i​o​n​M​a​n​a​g​e​r​ ​*​)​m​a​n​a​g​e​r​
 ​ ​ ​ ​ ​ ​ ​d​i​d​F​a​i​l​W​i​t​h​E​r​r​o​r​:​(​N​S​E​r​r​o​r​ ​*​)​e​r​r​o​r​;​
@​e​n​d​

This protocol, like all protocols, is declared with the directive @protocol followed by its name, CLLocationManagerDelegate. The NSObject in angled brackets refers to the NSObject protocol and tells us that CLLocationManagerDelegate includes all of the methods in the NSObject protocol. The methods specific to CLLocationManagerDelegate are declared next, and then the protocol is closed with an @end directive.

Note that a protocol is not a class; it is simply a list of methods. You cannot create instances of a protocol, it cannot have instance variables, and these methods are not implemented anywhere in the protocol. Instead, the implementation is left to each class that conforms to the protocol.

We call protocols used for delegation delegate protocols, and the naming convention for a delegate protocol is the name of the delegating class plus the word Delegate. Not all protocols are delegate protocols, however, and we will see an example of a different kind of protocol in the next chapter.

All of the protocols we’ve mentioned so far are part of the iOS SDK, but you can also write your own protocols. We’ll do that later in Chapter 14 and Chapter 26.

Protocol methods

In the CLLocationManagerDelegate protocol, we see two types of methods: methods that handle information updates and methods that handle requests for input. For example, the location manager’s delegate implements the locationManager:didEnterRegion: method if it wants to hear from the location manager that the device has entered a particular region. On the other hand, locationManagerShould​DisplayHeadingCalibration: is the message a location manager sends its delegate to ask if it should display the heading calibration. The method returns a BOOL value, which is the delegate’s answer.

Methods declared in a protocol can be required or optional. By default, protocol methods are required. If a protocol has optional methods, these are preceded by the directive @optional. Looking back at the CLLocationManagerDelegate protocol, you can see that all of its methods are optional. This is typically true of delegate protocols.

Before sending an optional method, the object first asks its delegate by sending another message, respondsToSelector:. Every object implements this method, which checks at runtime whether an object implements a given method. You can turn a selector into a value you can pass as an argument with the @selector() directive. For example, CLLocationManager could implement a method that looks like this:

-​ ​(​v​o​i​d​)​f​i​n​i​s​h​e​d​F​i​n​d​i​n​g​L​o​c​a​t​i​o​n​:​(​C​L​L​o​c​a​t​i​o​n​ ​*​)​n​e​w​L​o​c​a​t​i​o​n​
{​
 ​ ​ ​ ​/​/​ ​l​o​c​a​t​i​o​n​M​a​n​a​g​e​r​:​d​i​d​U​p​d​a​t​e​T​o​L​o​c​a​t​i​o​n​:​f​r​o​m​L​o​c​a​t​i​o​n​:​
 ​ ​ ​ ​/​/​ ​i​s​ ​a​n​ ​o​p​t​i​o​n​a​l​ ​m​e​t​h​o​d​,​ ​s​o​ ​w​e​ ​c​h​e​c​k​ ​f​i​r​s​t​.​
 ​ ​ ​ ​S​E​L​ ​u​p​d​a​t​e​M​e​t​h​o​d​ ​=​ ​@​s​e​l​e​c​t​o​r​(​l​o​c​a​t​i​o​n​M​a​n​a​g​e​r​:​d​i​d​U​p​d​a​t​e​T​o​L​o​c​a​t​i​o​n​:​f​r​o​m​L​o​c​a​t​i​o​n​:​)​;​

 ​ ​ ​ ​i​f​ ​(​[​[​s​e​l​f​ ​d​e​l​e​g​a​t​e​]​ ​r​e​s​p​o​n​d​s​T​o​S​e​l​e​c​t​o​r​:​u​p​d​a​t​e​M​e​t​h​o​d​]​)​ ​{​
 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​I​f​ ​t​h​e​ ​m​e​t​h​o​d​ ​i​s​ ​i​m​p​l​e​m​e​n​t​e​d​,​ ​t​h​e​n​ ​w​e​ ​s​e​n​d​ ​t​h​e​ ​m​e​s​s​a​g​e​.​
 ​ ​ ​ ​ ​ ​ ​ ​[​[​s​e​l​f​ ​d​e​l​e​g​a​t​e​]​ ​l​o​c​a​t​i​o​n​M​a​n​a​g​e​r​:​s​e​l​f​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​d​i​d​U​p​d​a​t​e​T​o​L​o​c​a​t​i​o​n​:​n​e​w​L​o​c​a​t​i​o​n​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​f​r​o​m​L​o​c​a​t​i​o​n​:​o​l​d​L​o​c​a​t​i​o​n​]​;​
 ​ ​ ​ ​}​
}​

If a method in a protocol is required, then the message will be sent without checking first. This means that if the delegate does not implement that method, an unrecognized selector exception will be thrown, and the application will crash.

To prevent this from happening, the compiler will insist that a class implement the required methods in a protocol. But, in order for the compiler to know to check for these methods, the class must explicitly state that it conforms to a protocol. This is done in the class header file: the protocols that a class conforms to are added to a comma-delimited list inside angled brackets in the interface declaration following the superclass.

In WhereamiAppDelegate.h, declare that WhereamiAppDelegate conforms to the CLLocationManagerDelegate protocol.

@​i​n​t​e​r​f​a​c​e​ ​W​h​e​r​e​a​m​i​A​p​p​D​e​l​e​g​a​t​e​ ​:​ ​N​S​O​b​j​e​c​t​
 ​ ​ ​ ​<​U​I​A​p​p​l​i​c​a​t​i​o​n​D​e​l​e​g​a​t​e​,​ ​C​L​L​o​c​a​t​i​o​n​M​a​n​a​g​e​r​D​e​l​e​g​a​t​e​>​

Build the application again. (Now that you’ve declared that WhereamiAppDelegate conforms to the CLLocationManagerDelegate protocol, the warning from the line of code where you set the delegate of the locationManager disappears.)

Notice the UIApplicationDelegate protocol in this declaration. The method application:​didFinishLaunchingWithOptions: is from the UIApplicationDelegate protocol. It’s a message that the UIApplication can send its delegate when the application is done launching and is about to start accepting user input. For Whereami, the delegate of the UIApplication is the instance of WhereamiAppDelegate. (The template set this property for you.) So, that delegate method is declared in the UIApplicationDelegate protocol and implemented in WhereamiAppDelegate.m.

Delegation, controllers, and memory management

From the perspective of the model-view-controller pattern, WhereamiAppDelegate is a controller object. It is typically the case that delegates are controller objects.

Delegates are never retained by their delegating objects. Why? Consider WhereamiAppDelegate. It owns locationManager and is also the delegate of locationManager. If the locationManager retained the WhereamiAppDelegate, these two objects would own each other and create something called a retain cycle. We will discuss retain cycles in more depth in Chapter 6, but the idea is if two objects retain each other, then they will never be deallocated.

To avoid retain cycles, delegate properties use the assign attribute instead of retain or copy. We call this a weak reference, where an object has a pointer to another object but does not retain it.

@​p​r​o​p​e​r​t​y​ ​(​n​o​n​a​t​o​m​i​c​,​ ​a​s​s​i​g​n​)​ ​i​d​ ​d​e​l​e​g​a​t​e​;​

Remember that the point of owning an object is that you can rely on its existence and will never get caught sending messages to an object that doesn’t exist. So, if an object cannot retain its delegate, then the delegate must be responsible and tell the object when it is being deallocated.

In this application, however, the WhereamiAppDelegate instance never gets deallocated. Check for yourself – place an NSLog in WhereamiAppDelegate’s dealloc, and you’ll never see it. Some controller objects are made to exist the entire time an application is running, and this is always the case for the AppDelegate. For classes like this, we typically don’t bother writing dealloc methods. When you first begin programming for iOS, it may be difficult to determine whether a controller will be destroyed. When you aren’t sure, you should implement dealloc – it never hurts to do so.

So let’s go ahead and examine what WhereamiAppDelegate’s dealloc method would look like if we were to implement it. We know it needs to remove itself as the location manager’s delegate. But there is one other important thing it must do – release the locationManager instance variable.

-​ ​(​v​o​i​d​)​d​e​a​l​l​o​c​
{​
 ​ ​ ​ ​i​f​(​[​l​o​c​a​t​i​o​n​M​a​n​a​g​e​r​ ​d​e​l​e​g​a​t​e​]​ ​=​=​ ​s​e​l​f​)​
 ​ ​ ​ ​ ​ ​ ​ ​[​l​o​c​a​t​i​o​n​M​a​n​a​g​e​r​ ​s​e​t​D​e​l​e​g​a​t​e​:​n​i​l​]​;​

 ​ ​ ​ ​[​l​o​c​a​t​i​o​n​M​a​n​a​g​e​r​ ​r​e​l​e​a​s​e​]​;​
 ​ ​ ​ ​[​w​i​n​d​o​w​ ​r​e​l​e​a​s​e​]​;​
 ​ ​ ​ ​[​s​u​p​e​r​ ​d​e​a​l​l​o​c​]​;​
}​

As you learned in the last chapter, releasing instance variables when an object is deallocated is important for freeing up memory and avoiding memory leaks. The object pointed to by locationManager is owned by the instance of WhereamiAppDelegate because you alloc’ed it in application:​didFinishLaunchingWithOptions:. So, if the WhereamiAppDelegate was ever going to be destroyed, it would need to release locationManager in dealloc.

Note that the possibility of not implementing dealloc is for controller objects only; model and view objects should always have dealloc methods. Also, keep in mind that each of your applications so far has only had a single controller object, the AppDelegate. Soon, you’ll build applications that have multiple controllers, some of which will definitely need to be deallocated. We will return to this discussion once we start building more complicated applications.

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

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