Objective-C Programming_ The Big Nerd Ranch Guide - Aaron Hillegass [54]
In main.m, create an instance of Logger and make it the target of an instance of NSTimer. Set the action to be the selector for sayOuch:.
#import #import "Logger.h" int main (int argc, const char * argv[]) { @autoreleasepool { Logger *logger = [[Logger alloc] init]; NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:logger selector:@selector(sayOuch:) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] run]; } return 0; } Build and run the program. (You will get an unused variable warning. Ignore it for now.) You should see Ouch! appear in the console every 2 seconds. Note that the colon is part of the selector. @selector(sayOuch) is not equal to @selector(sayOuch:). Take a second look at the warning from the compiler. It is saying, “Hey, you created the variable timer, but didn’t use it.” In some settings, like this one, you need to flag a variable as purposefully unused to silence the warnings. This is done with the __unused modifier. Add that now. __unused NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:logger selector:@selector(sayOuch:) userInfo:nil repeats:YES]; Build it again, and the warning should be gone. Helper objects In Chapter 23, you used an NSURLConnection method to fetch data from a web server. It worked fine, but there are two problems with the method: It blocks the main thread while waiting for all the data to arrive. If you used this method in a real application, the user interface would become unresponsive while the data was fetched. It has no way to callback if, for example, the webserver demands a username and password. For these reasons, we typically use an NSURLConnection asynchronously. That is, we start it fetching and then await callbacks as the data arrives or the web server demands credentials or the fetch fails. How do you get these callbacks? You supply the NSURLConnection with a helper object. When things happen, the connection sends messages to the helper object. What messages? The guy who wrote NSURLConnection made up a protocol – a list of method declarations – that the helper object can implement. Here are some of the methods in that protocol: - (NSURLRequest *)connection:(NSURLConnection *)c willSendRequest:(NSURLRequest *)req redirectResponse:(NSURLResponse *)res; - (void)connection:(NSURLConnection *)sender didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)ch; - (void)connection:(NSURLConnection *)sender didReceiveData:(NSData *)data; - (void)connectionDidFinishLoading:(NSURLConnection *)sender; - (void)connection:(NSURLConnection *)sender didFailWithError:(NSError *)error; - (NSCachedURLResponse *)connection:(NSURLConnection *)sender willCacheResponse:(NSCachedURLResponse *)cachedResponse; As you can see, an NSURLConnection lives a much richer life than an NSTimer. Now you are going to create an object that implements some or all of these methods and then introduce that object to the NSURLConnection as its helper object. In particular, the NSURLConnection has a pointer called delegate. Figure 24.4 Logger is the delegate of the NSURLConnection In main(), create an NSURLConnection and set the instance of Logger to be its delegate: #import #import "Logger.h" int main (int argc, const char * argv[]) { @autoreleasepool { Logger *logger = [[Logger alloc] init]; NSURL *url = [NSURL URLWithString: @"http://www.gutenberg.org/cache/epub/205/pg205.txt"]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; __unused NSURLConnection *fetchConn = [[NSURLConnection alloc] initWithRequest:request delegate:logger
Timers are simple. They only do one thing: fire. Thus, target-action is a good fit. A lot of simple user interface controls, like buttons and sliders, also use the target-action mechanism. What about something more complex?