Helper objects

In Chapter 26, you used an NSURLConnection to fetch data from a web server. This connection was synchronous – all the data was delivered at one time. It worked fine, but there are two problems with a synchronous connection:

  • It blocks the main thread while waiting for all the data to arrive. If you use this type of connection in an interactive application, the user interface will be unresponsive while the data was fetched.

  • It has no way to call back if, for example, the web server asks for a username and password.

For these reasons, it is more common to use an NSURLConnection asynchronously. In an asynchronous connection, the data comes in chunks rather than all at once. This means that there are connection-related events that you must be ready to respond to. Some examples of connection-related events are a chunk of data arrives, the web server demands credentials, and the connection fails.

To manage this more complex connection, you must give it a helper object. In the helper object, you implement the methods to be executed in response to different connection-related events.

In your Callbacks program, you are going to use an asynchronous NSURLConnection to fetch data from a website. The instance of BNRLogger will serve as the NSURLConnection’s helper object. More specifically, the BNRLogger will be the delegate of the NSURLConnection.

Figure 27.2  BNRLogger is the delegate of the NSURLConnection

BNRLogger is the delegate of the NSURLConnection

In main.m, create an NSURL and an NSURLRequest like you did in Chapter 26. Then create an NSURLConnection and set the instance of BNRLogger to be its delegate:

#​i​m​p​o​r​t​ ​<​F​o​u​n​d​a​t​i​o​n​/​F​o​u​n​d​a​t​i​o​n​.​h​>​
#​i​m​p​o​r​t​ ​"​B​N​R​L​o​g​g​e​r​.​h​"​

i​n​t​ ​m​a​i​n​ ​(​i​n​t​ ​a​r​g​c​,​ ​c​o​n​s​t​ ​c​h​a​r​ ​*​ ​a​r​g​v​[​]​)​
{​
 ​ ​ ​ ​@​a​u​t​o​r​e​l​e​a​s​e​p​o​o​l​ ​{​

 ​ ​ ​ ​ ​ ​ ​ ​B​N​R​L​o​g​g​e​r​ ​*​l​o​g​g​e​r​ ​=​ ​[​[​B​N​R​L​o​g​g​e​r​ ​a​l​l​o​c​]​ ​i​n​i​t​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​N​S​U​R​L​ ​*​u​r​l​ ​=​ ​[​N​S​U​R​L​ ​U​R​L​W​i​t​h​S​t​r​i​n​g​:​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​@​"​h​t​t​p​:​/​/​w​w​w​.​g​u​t​e​n​b​e​r​g​.​o​r​g​/​c​a​c​h​e​/​e​p​u​b​/​2​0​5​/​p​g​2​0​5​.​t​x​t​"​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​N​S​U​R​L​R​e​q​u​e​s​t​ ​*​r​e​q​u​e​s​t​ ​=​ ​[​N​S​U​R​L​R​e​q​u​e​s​t​ ​r​e​q​u​e​s​t​W​i​t​h​U​R​L​:​u​r​l​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​_​_​u​n​u​s​e​d​ ​N​S​U​R​L​C​o​n​n​e​c​t​i​o​n​ ​*​f​e​t​c​h​C​o​n​n​ ​=​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​[​[​N​S​U​R​L​C​o​n​n​e​c​t​i​o​n​ ​a​l​l​o​c​]​ ​i​n​i​t​W​i​t​h​R​e​q​u​e​s​t​:​r​e​q​u​e​s​t​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​d​e​l​e​g​a​t​e​:​l​o​g​g​e​r​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​s​t​a​r​t​I​m​m​e​d​i​a​t​e​l​y​:​Y​E​S​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​_​_​u​n​u​s​e​d​ ​N​S​T​i​m​e​r​ ​*​t​i​m​e​r​ ​=​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​[​N​S​T​i​m​e​r​ ​s​c​h​e​d​u​l​e​d​T​i​m​e​r​W​i​t​h​T​i​m​e​I​n​t​e​r​v​a​l​:​2​.​0​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​t​a​r​g​e​t​:​l​o​g​g​e​r​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​s​e​l​e​c​t​o​r​:​@​s​e​l​e​c​t​o​r​(​u​p​d​a​t​e​L​a​s​t​T​i​m​e​:​)​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​u​s​e​r​I​n​f​o​:​n​i​l​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​r​e​p​e​a​t​s​:​Y​E​S​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​[​[​N​S​R​u​n​L​o​o​p​ ​c​u​r​r​e​n​t​R​u​n​L​o​o​p​]​ ​r​u​n​]​;​

 ​ ​ ​ ​}​
 ​ ​ ​ ​r​e​t​u​r​n​ ​0​;​
}​

Now, in BNRLogger, you need to implement the callback methods – the methods to be executed in response to specific events.

You do not come up with or declare these methods yourself. They have already been declared in a protocol. A protocol is a list of method declarations. You will learn more about protocols in Chapter 29, but for now, think of a protocol as a prearranged set of messages that an object can send its helper object.

In BNRLogger.h, declare that BNRLogger will implement methods from the NSURLConnectionDelegate and NSURLConnectionDataDelegate protocols:

#​i​m​p​o​r​t​ ​<​F​o​u​n​d​a​t​i​o​n​/​F​o​u​n​d​a​t​i​o​n​.​h​>​

@​i​n​t​e​r​f​a​c​e​ ​B​N​R​L​o​g​g​e​r​ ​:​ ​N​S​O​b​j​e​c​t​
 ​ ​ ​ ​ ​ ​<​N​S​U​R​L​C​o​n​n​e​c​t​i​o​n​D​e​l​e​g​a​t​e​,​ ​N​S​U​R​L​C​o​n​n​e​c​t​i​o​n​D​a​t​a​D​e​l​e​g​a​t​e​>​

@​p​r​o​p​e​r​t​y​ ​(​n​o​n​a​t​o​m​i​c​)​ ​N​S​D​a​t​e​ ​*​l​a​s​t​T​i​m​e​;​
-​ ​(​N​S​S​t​r​i​n​g​ ​*​)​l​a​s​t​T​i​m​e​S​t​r​i​n​g​;​
-​ ​(​v​o​i​d​)​u​p​d​a​t​e​L​a​s​t​T​i​m​e​:​(​N​S​T​i​m​e​r​ ​*​)​t​;​
@​e​n​d​

There are three messages that BNRLogger will need to respond to as the delegate of the NSURLConnection. Two are from the NSURLConnectionDataDelegate protocol:

-​ ​(​v​o​i​d​)​c​o​n​n​e​c​t​i​o​n​:​(​N​S​U​R​L​C​o​n​n​e​c​t​i​o​n​ ​*​)​c​o​n​n​e​c​t​i​o​n​
 ​ ​ ​ ​d​i​d​R​e​c​e​i​v​e​D​a​t​a​:​(​N​S​D​a​t​a​ ​*​)​d​a​t​a​;​

-​ ​(​v​o​i​d​)​c​o​n​n​e​c​t​i​o​n​D​i​d​F​i​n​i​s​h​L​o​a​d​i​n​g​:​(​N​S​U​R​L​C​o​n​n​e​c​t​i​o​n​ ​*​)​c​o​n​n​e​c​t​i​o​n​;​

The other is from the NSURLConnectionDelegate protocol:

-​ ​(​v​o​i​d​)​c​o​n​n​e​c​t​i​o​n​:​(​N​S​U​R​L​C​o​n​n​e​c​t​i​o​n​ ​*​)​c​o​n​n​e​c​t​i​o​n​
 ​ ​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​;​

(How do you know what methods a protocol has and which ones you should implement? Go to the developer documentation. Protocols have references, similar to class references, with information about their methods. You will also learn more about protocols and their methods in Chapter 29.)

Before you get to implementing these methods, BNRLogger needs a new instance variable. When you created a synchronous NSURLConnection in Chapter 26, you used an instance of NSData to hold the bytes coming from the server. In an asynchronous connection, you need an instance of NSMutableData. As the chunks of data arrive, you will add them to this object.

In BNRLogger.h, add an NSMutableData instance variable:

#​i​m​p​o​r​t​ ​<​F​o​u​n​d​a​t​i​o​n​/​F​o​u​n​d​a​t​i​o​n​.​h​>​

@​i​n​t​e​r​f​a​c​e​ ​B​N​R​L​o​g​g​e​r​ ​:​ ​N​S​O​b​j​e​c​t​
 ​ ​ ​ ​ ​ ​<​N​S​U​R​L​C​o​n​n​e​c​t​i​o​n​D​e​l​e​g​a​t​e​,​ ​N​S​U​R​L​C​o​n​n​e​c​t​i​o​n​D​a​t​a​D​e​l​e​g​a​t​e​>​

{​
 ​ ​ ​ ​N​S​M​u​t​a​b​l​e​D​a​t​a​ ​*​_​i​n​c​o​m​i​n​g​D​a​t​a​;​
}​
@​p​r​o​p​e​r​t​y​ ​(​n​o​n​a​t​o​m​i​c​)​ ​N​S​D​a​t​e​ ​*​l​a​s​t​T​i​m​e​;​
-​ ​(​N​S​S​t​r​i​n​g​ ​*​)​l​a​s​t​T​i​m​e​S​t​r​i​n​g​;​
-​ ​(​v​o​i​d​)​u​p​d​a​t​e​L​a​s​t​T​i​m​e​:​(​N​S​T​i​m​e​r​ ​*​)​t​;​
@​e​n​d​

In BNRLogger.m, implement the three protocol methods:

#​i​m​p​o​r​t​ ​"​B​N​R​L​o​g​g​e​r​.​h​"​

@​i​m​p​l​e​m​e​n​t​a​t​i​o​n​ ​B​N​R​L​o​g​g​e​r​

 ​ ​.​.​.​

/​/​ ​C​a​l​l​e​d​ ​e​a​c​h​ ​t​i​m​e​ ​a​ ​c​h​u​n​k​ ​o​f​ ​d​a​t​a​ ​a​r​r​i​v​e​s-​ ​(​v​o​i​d​)​c​o​n​n​e​c​t​i​o​n​:​(​N​S​U​R​L​C​o​n​n​e​c​t​i​o​n​ ​*​)​c​o​n​n​e​c​t​i​o​n​
 ​ ​ ​ ​d​i​d​R​e​c​e​i​v​e​D​a​t​a​:​(​N​S​D​a​t​a​ ​*​)​d​a​t​a{​
 ​ ​ ​ ​N​S​L​o​g​(​@​"​r​e​c​e​i​v​e​d​ ​%​l​u​ ​b​y​t​e​s​"​,​ ​[​d​a​t​a​ ​l​e​n​g​t​h​]​)​;​

 ​ ​ ​ ​/​/​ ​C​r​e​a​t​e​ ​a​ ​m​u​t​a​b​l​e​ ​d​a​t​a​ ​i​f​ ​i​t​ ​d​o​e​s​ ​n​o​t​ ​a​l​r​e​a​d​y​ ​e​x​i​s​t​
 ​ ​ ​ ​i​f​ ​(​!​_​i​n​c​o​m​i​n​g​D​a​t​a​)​ ​{​
 ​ ​ ​ ​ ​ ​ ​ ​_​i​n​c​o​m​i​n​g​D​a​t​a​ ​=​ ​[​[​N​S​M​u​t​a​b​l​e​D​a​t​a​ ​a​l​l​o​c​]​ ​i​n​i​t​]​;​
 ​ ​ ​ ​}​

 ​ ​ ​ ​[​_​i​n​c​o​m​i​n​g​D​a​t​a​ ​a​p​p​e​n​d​D​a​t​a​:​d​a​t​a​]​;}/​/​ ​C​a​l​l​e​d​ ​w​h​e​n​ ​t​h​e​ ​l​a​s​t​ ​c​h​u​n​k​ ​h​a​s​ ​b​e​e​n​ ​p​r​o​c​e​s​s​e​d-​ ​(​v​o​i​d​)​c​o​n​n​e​c​t​i​o​n​D​i​d​F​i​n​i​s​h​L​o​a​d​i​n​g​:​(​N​S​U​R​L​C​o​n​n​e​c​t​i​o​n​ ​*​)​c​o​n​n​e​c​t​i​o​n{​
 ​ ​ ​ ​N​S​L​o​g​(​@​"​G​o​t​ ​i​t​ ​a​l​l​!​"​)​;​
 ​ ​ ​ ​N​S​S​t​r​i​n​g​ ​*​s​t​r​i​n​g​ ​=​ ​[​[​N​S​S​t​r​i​n​g​ ​a​l​l​o​c​]​ ​i​n​i​t​W​i​t​h​D​a​t​a​:​_​i​n​c​o​m​i​n​g​D​a​t​a​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​e​n​c​o​d​i​n​g​:​N​S​U​T​F​8​S​t​r​i​n​g​E​n​c​o​d​i​n​g​]​;​
 ​ ​ ​ ​_​i​n​c​o​m​i​n​g​D​a​t​a​ ​=​ ​n​i​l​;​
 ​ ​ ​ ​N​S​L​o​g​(​@​"​s​t​r​i​n​g​ ​h​a​s​ ​%​l​u​ ​c​h​a​r​a​c​t​e​r​s​"​,​ ​[​s​t​r​i​n​g​ ​l​e​n​g​t​h​]​)​;​

 ​ ​ ​ ​/​/​ ​U​n​c​o​m​m​e​n​t​ ​t​h​e​ ​n​e​x​t​ ​l​i​n​e​ ​t​o​ ​s​e​e​ ​t​h​e​ ​e​n​t​i​r​e​ ​f​e​t​c​h​e​d​ ​f​i​l​e​
 ​ ​ ​ ​/​/​ ​N​S​L​o​g​(​@​"​T​h​e​ ​w​h​o​l​e​ ​s​t​r​i​n​g​ ​i​s​ ​%​@​"​,​ ​s​t​r​i​n​g​)​;}/​/​ ​C​a​l​l​e​d​ ​i​f​ ​t​h​e​ ​f​e​t​c​h​ ​f​a​i​l​s-​ ​(​v​o​i​d​)​c​o​n​n​e​c​t​i​o​n​:​(​N​S​U​R​L​C​o​n​n​e​c​t​i​o​n​ ​*​)​c​o​n​n​e​c​t​i​o​n​
 ​ ​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{​
 ​ ​ ​ ​N​S​L​o​g​(​@​"​c​o​n​n​e​c​t​i​o​n​ ​f​a​i​l​e​d​:​ ​%​@​"​,​ ​[​e​r​r​o​r​ ​l​o​c​a​l​i​z​e​d​D​e​s​c​r​i​p​t​i​o​n​]​)​;​
 ​ ​ ​ ​_​i​n​c​o​m​i​n​g​D​a​t​a​ ​=​ ​n​i​l​;}​

@​e​n​d​

Build and run the program. You will see the data coming from the web server in chunks. Eventually, the BNRLogger will be informed that the fetch is complete.

Here are the rules, so far, for callbacks: When sending one callback to one object, Apple uses target-action. When sending an assortment of callbacks to one object, Apple uses a helper object with a protocol. These helper objects are typically called delegates or data sources.

What if the callback needs to go to multiple objects?

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

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