Cocoa Programming for Mac OS X - Aaron Hillegass [108]
RanchForecast Project
It just so happens that the Big Nerd Ranch Web site has an XML feed of upcoming classes. In this exercise, you are going to write an application that uses this Web service to show the upcoming classes at Big Nerd Ranch in a table view. The app will look like Figure 28.4.
Figure 28.4. Completed Application
Create a new project of type Cocoa Application. Disable Create Document-Based Application, Uses Core Data, and Create Unit Tests. Name the project RanchForecast. Set the Class Prefix to RanchForecast also.
We’ll build this application from the model upward. Create a new Objective-C class called ScheduledClass that subclasses NSObject. Add four properties: name, location, href, and begin in ScheduledClass.h:
#import @interface ScheduledClass : NSObject { NSString *name; NSString *location; NSString *href; NSDate *begin; } @property (nonatomic, copy) NSString *name; @property (nonatomic, copy) NSString *location; @property (nonatomic, copy) NSString *href; @property (nonatomic, strong) NSDate *begin; @end Then synthesize the properties in ScheduledClass.m: #import "ScheduledClass.h" @implementation ScheduledClass @synthesize name, location, href, begin; @end With a simple model, it can often be tempting to use an NSDictionary. Frequently, however, taking the time to create a class will make life easier in the long run, especially when a project grows beyond its initial scope. NSURLConnection NSURLConnection can be used synchronously and asynchronously. In a synchronous connection, the current thread blocks while the request is completed, making it unsuitable for use in the main thread, as this will make the user interface unresponsive while the request is completed. Asynchronous connections are scheduled in the run loop, and a delegate is specified to respond to various events in the connection’s lifetime. In this chapter, we will use an synchronous connection for simplicity. Create a new subclass of NSObject called ScheduleFetcher. This class will encapsulate the hard work of communicating with the Web service and parsing the result into the model object. By abstracting away this functionality, we keep our user interface controller classes simple and uncluttered, and we can easily use this class in other projects. Define the interface in ScheduleFetcher.h: #import @interface ScheduleFetcher : NSObject NSMutableArray *classes; NSMutableString *currentString; NSMutableDictionary *currentFields; NSDateFormatter *dateFormatter; } // Returns an NSArray of ScheduledClass objects if successful. // Returns nil on failure. - (NSArray *)fetchClassesWithError:(NSError **)outError; @end Define init and fetchClassesWithError: in ScheduleFetcher.m: #import "ScheduleFetcher.h" #import "ScheduledClass.h" @implementation ScheduleFetcher - (id)init { self = [super init]; if (self) { classes = [[NSMutableArray alloc] init]; dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss zzzz"]; } return self; } - (NSArray *)fetchClassesWithError:(NSError **)outError { NSURL *xmlURL = [NSURL URLWithString: @"http://bignerdranch.com/xml/schedule"]; NSURLRequest *req = [NSURLRequest requestWithURL:xmlURL cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:30]; NSURLResponse *resp = nil; NSData *data = [NSURLConnection sendSynchronousRequest:req returningResponse:&resp error:outError]; if
Now that we have the model defined, we will turn our attention to fetching the data from the Web service. In Cocoa, this is typically done using the NSURLConnection class. In order to create a connection, we must first create an NSURLRequest, which describes the request to the connection object. NSURLRequest is sufficient for simple requests. Requests requiring more conrol, such as specific request headers, should use NSMutableURLRequest.