Weblog

Ab Initio

This blog is going to talk about my experiences and frustrations as a software developer. A lot of what I write about is for my own personal edification and not necessarily intented for human consumption. Read at your own risk.

You can find the RSS feed here.

Summer Time

That last six months have been interesting, with many things happening.

- Updated Hansel,
- Started worked with Nibisoftware Group and got their iPhone/iPad app into the store,
- Created Contacts Map and have updated it several times with lots of great feedback,
- Continued working on NDA project for Social Networking,
- Started preliminary work on a remote control project for the Mac/iOS

This was of course outside of my regular 9-5 routine, which has recently changed. I have accepted a position as an iPad developer at Thompson-Reuters working on their next gen Westlaw application. I am very excited and this will definitely take my career to the next level. 

I wish that I could have been more active on my weblog, but all of this coding has gotten in the way of that. I still want to do a series on Apache CXF/JAX-RS/iOS, and am hoping that I can get to work on that soon. As of now I just don't have the time.

iPad after a few weeks

Now that I've been working with the iPad for a few weeks, I really like what Apple has done with the development process. 

Making Hybrid iPhone/iPad applications is very easy for existing iPhone apps. You simply open up the xib in IB and select the File -> Create iPad version menu option. That combined with UI_USER_INTERFACE_IDIOM() and you can reuse all your existing view controllers while having full control over how you handle specific devices. 

I think there merit in making hybrid apps from existing iPhone apps in many cases. Nibipedia for instance is a perfect candidate for this. It is a small lightweight app that is mostly UIWebView driven. There isn't a lot of UI code for animations or dynamic view creation. It makes sense to just create a hybrid app.

Hansel on the other hand is more complicated. My initial attempt to make a hybrid app has failed miserably. The main problem is that I have lots of UI code that moves views around and makes assumptions about the device, that it is indeed an iPhone. While I could have written it in a more generic fashion, I never felt the need to do so. It didn't seem like there was enough benefit for spending the extra time on a free app. 

The thing with UI animation code is that it tends to not be as reusable. Some of the code I am able to reuse via clipboard inheritance. However, I created those effects specifically for Hansel and not with the intention of reusing them or for that matter with the intent of supporting the iPad or any other device. I will end up creating separate iPad view controllers for Hansel, if and when I get around to porting it. There really isn't a big need for me to do so. I created Hansel as a free app so I could easily show my iPhone app development skills. It was created to be a simple application and it will probably stay that way on the iPhone only. 

Back to the topic at hand. Creating Contacts Map was a great experience. It is meant to be an iPad only app. While it could be done on the iPhone pretty easily, the iPad is perfect for this app (or maybe this app is perfect for the iPad...). Again, I am doing this work to show that I can do iPad development and that I am capable with both the SDK and web service consumption. It will be up in the app store soon, I just have to find an icon for it and I'll be good to go.

I have a good concept for my next application involving the iPad, which will also have a Mac component. It centers around remote control of the Mac for machines setup as media centers. More on that next time.

Hansel Crash Reports

While submitting Hansel 1.5, I decided to snoop around iTunes Connect. I hadn't really looked at the site much recently and Apple has been busy updating it for the iPad. To my distinct amusement, I saw this message.


New Year

I started a new job over the new year. Working for ITR Group was a good experience but they lacked direction and leadership. I was the senior most engineer out of a team of 6. It was enjoyable but I'm glad it is over. I have iPhone work I'm doing on the side, so I still get my fix.

Back at McKesson, I am now working with GWT, Java, and RDF. It is interesting work and I am happy to broaden my skill set. I forgot how challenging working with Eclipse can be, but I plan to work with CXF web services to expose data to the iPhone. I'll be writing a set of articles about that in the coming months.

Projects

I've been working on a couple of projects since my last blog post. I plan to have the next installment on Data Services done by the end of the week. There will probably be 2 more posts in the series after that.

Hansel has been submitted to the app store for review. I'm waiting to hear back from Apple, probably another 5-10 days. I added a new page about the app. It explains how to use the app and provides a way for users to leave feedback.

My only real concern is that it will get rejected for the way I handle current generation iPods. If I do not detect a camera, then a message is displayed instead of the image picker UI. The interface guidelines doc specifies that functionality which is not available should not be displayed. I tested on an iPod at the last minute and decided for a quick fix so I could indicate that it is supported. Other than camera support, the app works flawlessly on the 2nd gen iPod Touches. 

I've also been working on a project that involves social networking. Due to NDA, I'm unable to talk about it in any detail. Suffice it to say, it is a pretty cool project :)

CarDealer

This is the fourth installment about using and accessing RESTful webservices on the iPhone.

You can download the example project artifacts here. This includes the iPhone example project and SQL Server scripts for generating the CarDealer DB and demo data.


Getting Started with iPhone + Data Services

Getting this post out took much longer than I thought. Setting up my .NET development and hosting environment was painful. My personal environment is different from my work environment, so I had some catch up after several months of not using it. 

Setting up SQL Server Express was not bad at all. I had an older version and decided to upgrade it to '08. Trying to create the data services project was painless as well. The pain began when I tried deploying to IIS 6 locally. While I'm sure someone out there can do it, I was unable to make it work. I decided to setup a Windows Server '08 VM to ease the pain. It helped a lot, but was very time consuming.

I started looking around for a free .NET hosting service that I could use to make the services public for the example. After several hours a gave up on this. I could have paid for a cheap one, but I doubt that I'd ever use it for anything else. 

I then took some cycles and looked at using Azure. I do not have Vista (XP ftw) for my dev environment and could not install the SDK required for deployment. I was able to setup an Azure SQL database and import all of my example tables, but without being able to deploy the data services from the cloud it was useless. 

Please note that my indication of wanting to use Azure for this example is not representative of my being a cloud advocate. Cloud computing, like most other technologies, has its uses in certain circumstances but it is not and will never be a silver bullet.


Setting up the backend

I finally decided that I would just make the database scripts available and point people to this article on creating data services. If you have the prerequisites below, then it should take less than half an hour to be up and running. I suggest naming it CarDealer.svc. I apologize for not supplying the source, but I don't want to have to muck around with cleaning out my connection strings and such. It is fairly easy and you will probably need to setup new data services in the future, so why not get some practice.

In order to setup the necessary backend you will need VS '08 SP1 [or later], SQL Server Express '08 [any version may work], and IIS 7.0. The key is deploying the data service is a way that is visible to the iPhone/Simulator. If you cannot load the CarDealer.svc in a browser on the client platform then you will not be able to use the data service in the iPhone example.

To make the iPhone example work with your services, modify the kServicesURL constant found in CarDealerAppDelegate. It should point to the fully qualified URL of your deployed CarDealer.svc.


Car Dealer

For this example I chose to model something that demonstrates relationships. Relationships are one of the learning curves with the current implementation of ADO.NET Data Services.

This system is used to store information about people, their cars, and any maintenance that has been performed on those cars. It is geared toward a maintenance department, not a sales team. It is something that is simple but non-trivial. There are a couple of primitive data elements and then tables to represent many-to-many relationship between those elements. 

edm

Bigger Version

The Example

Once you have everything running, and configured to point to your shiny new services, you will be presented with the screen on the right. It is a simple UI that displays a list of people in the system. Selecting a person will reveal their cars. Picking a car will show its maintenance records.

Like all my examples in this series, this one is plain, out-of-the-box, and meant to be a technology demonstration. Don't submit these to the app store and expect to win a design award.


Person

The Code

RestConnection has been updated in this example. The BSJSONAdditions have also been brought into the project, but are unchanged in this example.

I'm going to talk about the interesting code below. I will not go into the mundane details of UINavigationController et al. You can find more info on that here.


RestConnection

There are a couple of modifications to RestConnection. 

Data Services has a couple of nuances. First, it always wraps its responses in a root object, "d". Second, a data service can expose resources that are either singular or plural. If a solitary resource is specified by a URL, then the root object will contain a single object [dictionary]. If the resource specifies a group of objects, then the root object will contain an array. 

It is up to the client to understand which will be returned. In order to better support this behavior, RestConnection has been extended to A) "unwrap" the data for us and B) provide an additional method, - (NSArray *)arrayData, for handling collections.


Person

The person view controller is meant to display all the people in the system. For a production environment this would have to be retooled so it supported paging and allowed for searching. That is out of the scope of this example but there will be a post about both concepts later.

In the viewDidLoad method, a RestConnection is setup for use by the screen. kServicesURL defines the absolute path to the .svc.

restConnection = [[RestConnection alloc] initWithBaseURL:kServicesURL];
restConnection.delegate = self;

In viewWillAppear a request is built that points to the Person resource. That object is then used to load the data.

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    NSMutableURLRequest *request =
        [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"Person"]];
    [restConnection performRequest:request];
    [request release];
}

Finally, in the finishedReceivingData method, the table view is told to reload itself.

- (void)finishedReceivingData:(NSData *)data
{
    [self.tableView reloadData];
}
The table view delegate methods are implemented to grab data out of the RestConnection and display it. Here is the code used by the cellForRowAtIndexPath to display the person name.
// Configure the cell.
NSDictionary *person = [restConnection.arrayData objectAtIndex:indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:@"%@, %@",
                            [person objectForKey:@"lastName"],
                            [person objectForKey:@"firstName"]];

Selecting a table cell causes a new view controller to be created, PersonCarViewController. The view controller is told which person it should be displaying information about and then push it on the stack.

PersonCarViewController *vc =
    [[PersonCarViewController alloc] initWithNibName:@"PersonCarViewController" bundle:nil];
vc.person = [[restConnection arrayData] objectAtIndex:indexPath.row];
[self.navigationController pushViewController:vc animated:YES];
[PersonCarViewController release];


PersonCar

PersonCar represents a relationship between a person and their cars. The screen the right displays a list of a person's cars. Selecting a car will display its maintenance history. PersonCar

This view controller is structured very similar to the Person view controller. The first difference is the request that gets built. Here cars are loaded for a specific person. The following code is used to format a URL which loads a person's resource, the associated PersonCars, and each PersonCars' Car.

NSString *resource = [NSString stringWithFormat:@"Person(%@)?$expand=PersonCar,PersonCar/Car", [person objectForKey:@"personID"]];

The syntax is a bit odd at first, most REST systems use a path component to specify unique identifiers, so it would be written like "Person/242134" instead of "Person(987234)". Other than that, we have the query string addition to expand the necessary information required by our UI.

So a request URI like this:

http://192.168.1.112/EDMTest/CarDealer.svc/Person(1)?$expand=PersonCar,PersonCar/Car

Would yield a response like this:

{"d":
    {"__metadata":
        {"uri":"http://192.168.1.112/EDMTest/CarDealer.svc/Person(1)",
         "type":"edmexampleModel.Person"},
     "personID":1,
     "firstName":"Bob",
     "lastName":"Samson",
     "ssn":"543872934",
     "createDate":"/Date(1257008908440)/",
     "PersonCar":[
        {"__metadata":
            {"uri":"http://192.168.1.112/EDMTest/CarDealer.svc/PersonCar(1)",
             "type":"edmexampleModel.PersonCar"},
         "personCarID":1,
         "createStamp":"/Date(1257103813990)/",
         "Car":
            {"__metadata":
                {"uri":"http://192.168.1.112/EDMTest/CarDealer.svc/Car(2)",
                 "type":"edmexampleModel.Car"},
             "carID":2,
             "make":"Ford",
             "model":"Explorer",
             "manufactureDate":"/Date(1099242508440)/",
             "createStamp":"/Date(1257008940840)/",
             "PersonCar":
                {"__deferred":
                    {"uri":"http://192.168.1.112/EDMTest/CarDealer.svc/Car(2)/PersonCar"}}},
         "Person":
            {"__deferred":
                {"uri":"http://192.168.1.112/EDMTest/CarDealer.svc/PersonCar(1)/Person"}},
         "PersonCarMaintenance":
            {"__deferred":
                {"uri":"http://192.168.1.112/EDMTest/CarDealer.svc/PersonCar(1)/PersonCarMaintenance"}}},
        {"__metadata":
            {"uri":"http://192.168.1.112/EDMTest/CarDealer.svc/PersonCar(2)",
             "type":"edmexampleModel.PersonCar"},
         "personCarID":2,
         "createStamp":"/Date(1257109628720)/",
         "Car":
            {"__metadata":
                {"uri":"http://192.168.1.112/EDMTest/CarDealer.svc/Car(5)",
                 "type":"edmexampleModel.Car"},
             "carID":5,
             "make":"Ford",
             "model":"Mustang",
             "manufactureDate":"/Date(1075680000000)/",
             "createStamp":"/Date(1257109563660)/",
             "PersonCar":
                {"__deferred":
                    {"uri":"http://192.168.1.112/EDMTest/CarDealer.svc/Car(5)/PersonCar"}}},
         "Person":
            {"__deferred":
                {"uri":"http://192.168.1.112/EDMTest/CarDealer.svc/PersonCar(2)/Person"}},
         "PersonCarMaintenance":
            {"__deferred":
                {"uri":"http://192.168.1.112/EDMTest/CarDealer.svc/PersonCar(2)/PersonCarMaintenance"}}}]}}

As you can see there is a lot of crap in there. I'll talk about __deferred and __metadata later on, there is plenty of discussion to be had about them.

The UI wants to display each description of each car for the person in context. This is done in cellForRowAtIndex as such.

NSDictionary *car = [[personCars objectAtIndex:indexPath.row] objectForKey:@"Car"];
cell.textLabel.text = [car objectForKey:@"model"];

Once a car has been selected in the table, the car's maintenance history should display. A new view controller is instantiated and the selected PersonCar information passed on.


PersonCarMaintenance

This view controller is very similar to the PersonCar VC. The purpose is to display a list of maintenance activities for the car in context.

PersonCarMaint

This is the URL template that is used to get the required resources.

NSString *resource =
    [NSString stringWithFormat:@"Person(%@)?$expand=PersonCar,PersonCar/Car", [person objectForKey:@"personID"]];

And here is how we display the maintenance description.

NSDictionary *personCarMaintenance = [personCarMaintenances objectAtIndex:indexPath.row];
cell.textLabel.text =
    [[personCarMaintenance objectForKey:@"Maintenance"] objectForKey:@"description"];


Wrapping it up

So there you have it. I have discussed connecting an iPhone application an ADO.NET Data Service. Next time I'll talk more about this and discuss the CUD in CRUD.

Until next time, enjoy!

Sample Code Update

A reader pointed out a problem with the sample code where it would not compile. I tracked down the issue in RestConnection and fixed it. The data member has been renamed to responseData. This should fix the compilation problems.

Both sample code projects have been updated with the fix.

ADO.NET Data Services

This is the third installment about using and accessing RESTful webservices on the iPhone.

There is no example project associated with this post.


Astoria

[ADO.NET] Data Services is Microsoft's way of turning EDM into web services. While researching the best way to access data stored in an SQL Server database from the iPhone, we decided to give Data Services a go around. Superficially it matched our broad criteria for the project's services layer:

  • RESTful Interface,
  • JSON payload support,
  • Run on IIS,
  • Easily access SQL Server

Accessing it on the iPhone turned out to be very simple. After it was accessible via a browser I began working on displaying a simple table from the database. I created the first version of RestConnection and I was able to get a list of data primitives out of the database and displayed in a UITableView in about an hour.


Formats

Atom is the default format for Data Services. You can specify JSON by setting the Accept header on your HTTP requests. JSON is much easier to deal with on the iPhone because of it's simpler format. However, if you have a good Atom handling methodology than that format maybe preferable.


Options

Data Services has great functionality out of the box. Query options provide the ability to sort and filter result sets. The main thing that is missing is the ability to get a scalar value representing the results set (record/page counts). This has been addressed in the 4.0 version of the framework and will be available as part of the VS10 release (in beta already). See $inlinecount and $count for more information.


Service Document and Metadata

If you do a GET on the base service URL, it will return a service document. This xml contains information about the entities that are exposed via the Data Service.

If you append a /$metadata to your base service URL, you will get back an XML document containing Data Service Metadata. This information can be extremely useful for introspecting your Data Service. For example, it can be used in generating code to create a strongly typed business object.


Conclusion

This post has talked about ADO.NET Data Services and provided some useful links to get the basics down. Next time a coding example will show how to connect to a Data Service and parse the information, reusing and building on previous examples.

The next article can be found here.

Updates

The example code for the first 2 posts in the REST series have been updated. 

I discovered a problem with the willSendRequest delegate callback not being passed the current request. There was also a bug where the Accept header was not being defaulted to application/json if one did not exist.

JSON Handling

This is the second post in a series on accessing RESTful web services from the iPhone.
The example project used in this post can be downloaded here.

JSON

JSON has been around for about a decade now.  It has more recently become a popular alternative to XML because of both a smaller payload and a standardized format which focuses on associations and collections. WCF web services, for example, provide out of the box support for JSON as a data exchange format. After years of dealing with XML and various schemas, I prefer JSON's succinct style.


JSON + iPhone

As far as the iPhone is concerned, handling JSON is not currently built into any of the frameworks. For native development, there is nothing to specifically facilitate consuming or exporting JSON. However some people at Apple do recognize that JSON is widely used, as evident by both its support in Dashcode bindings and its use as the exchange format for APNs.

Because the JSON specification is extremely simple, this does not pose a problem for creating a JSON handling solution. The question always arises, should I find someone else's solution or roll my own? In my case, I take the lazy programmer approach. I am generally lazy unless I find the problem very interesting or I can't find something to suit my needs (in that order). Sometimes a problem *IS* very interesting and I want to solve it in my own way, as a personal challenge. Sadly business deadlines and schedules don't accommodate this very often. So to the end of being as lazy as possible, I found a very well written (complete with test cases!) JSON "library" that works on the iPhone.


BSJSONAdditions

I actually looked around at a couple of JSON handling "libraries" for the iPhone. BSJSONAdditions was the only one that had test cases and more than one contributor. What it lacked was specific support for EDM date types.  The JSON format does not have support for date as a first-class primitive type, only numbers and strings. Obviously no iPhone library I was going to find would have support for *THAT*, nor did I expect it to or even anticipate needing it (lesson learned there!). I will discuss EDM, EDM dates, and my additions to BSJSONAdditions [pun intended] in a later article.

This library translates JSON objects (name/value pairs) into NSDictionarys and JSON arrays into NSArrays. So given the following JSON:
{
    "myCoolObject" :
    [
        "value1",
        "value2"
    ]
}
BSJSONAdditions would create an NSDictionary with one entry, "myCoolObject". The value for "myCoolObject"'s entry would be an NSArray with 2 values, "value1" and "value2". 


The Example

This article will build on the previous post's project. Those classes will be modified and extended, as well as adding the BSJSONAdditions to the project. The primary focus of the changes will be on parsing the JSON data and displaying it in a UITableView. 

If you have not yet downloaded the source for this example, you can do so here.

This post is not about explaining what a UITableView is or does and assumes you know how to use one. Please referring to UITableView docs for more information.
searchwindow
The Project

The only new files are those under the BSJSON group, now at the top of the project.

   
RestConnection 

This class has been slightly extended to incorporate the BSJSONAdditions. As a convenience, there is now a new property for returning the response body as a parsed dictionary.
// Returns a dictionary representation of the last data received.
@property (nonatomic, readonly) NSDictionary *dictionaryData;

...
- (NSDictionary *)dictionaryData { return [NSDictionary dictionaryWithJSONString:[self stringData]]; }

SearchResultsViewController

This class has changed the most. The UITextView has been removed and replaced by a UITableView. The delegate and datasource have been set to the view controller.

The finishedReceivingData method has been changed to the following.
- (void)finishedReceivingData:(NSData *)data
{
    NSLog(@"finishedReceivingData: %@", [restConnection stringData]);
    [activityIndicator stopAnimating];

// Get the dictionary containing the raw parsed data. NSDictionary *rawData = [restConnection dictionaryData];
// Get the interesting search results data for display to the user. [tableData release]; tableData = [[[rawData objectForKey:@"responseData"] objectForKey:@"results"] retain]; [mainTableView reloadData]; }

A parsed dictionary representation of the data is now retrieved instead of the raw JSON. We reach into the responseData and get the results which contain the interesting information that our UI wants to display, search result information.

The table view methods section has also been added. These methods are for the table datasource and delegate implementation. Basically for each result we display a table row that shows a search result description and it's URL. Thats it, pretty simple and straight forward.


Conclusion

This post has mostly talked about JSON and how to parse it on the iPhone. The next post for the series will talk more about connecting to an EDM backed web service and some of the challenges that have to be overcome in doing so.

Until next time, enjoy.

RestConnection

This is the first post in a series on accessing RESTful web services from the iPhone.
The example project used in this post can be downloaded here.


REST

Unlike many other types of web services, all RESTful web services provide a uniform set of actions irrespective of their data entities. Every resource, or "noun", in a RESTful web service has the same set of methods, or "verbs", to do any and everything to that resource.

Resources are specified using HTTP URIs.  www.myurl.com/people could represent a collection of persons, while www.myurl.com/people/joebob would represent a single person. I should note that normally you would have your resources identified by a unique id, such as SSN or account number, and not by something like a name. That is a different discussion however.

The HTTP methods POST, GET, PUT, and DELETE map to basic CRUD (Create, Read, Update, and Delete respectively) very well. Non RESTful services may have methods like CreateWidget, UpdateTheThing, or RetrieveMySearchStuff. Under these schemes you would invoke different "verbs" depending on the "noun" you're handling.

Using our example URI above, if we do a GET on /people we would expect to get back all the persons in the collection. Doing a GET on /people/joebob should only return one person, joebob.


REST + iPhone

One of the great things about REST web services is that consuming them on the iPhone is easy. NSURLConnection provides all the functionality required to connect to a URI and transfer information in and out it. By simply building an NSURLRequest, you can perform all your CRUD operations via the NSURLConnection. We are going to simplify access to the NSURLConnection class through composition and object delegation. 

In any non-trivial client application, there are multiple objects in your data model. RestConnection will help to compose the commonalities of accessing those objects. It will also provide a way to persist information associated with the request; the NSURLRequest, NSURLResponse, and the response data.


The Example

I'm not necessarily a proponent of Google, however they provide some very useful web technologies that are very easy to use. For this article I'll be using their non-javascript AJAX search api. Though the RestConnection class will support all HTTP methods, I'll only be showcasing the GET functionality for now. We'll evolve the class as the articles progress.

In keeping with the classic search paradigm I'll keep the example very simple. The end result will look like screenshot on your right. The text field at the top allows search text to be entered and the text view on the bottom displays the results. You can grab the code here if you haven't already.

As will all future examples, this one assumes that you have an iPhone development environment already setup. If you don't then start here. This also assumes that you have a basic understanding of iPhone development. Some of the things I talk about may not make sense if you do not.

searchwindow

The Project

On top of a bare bones iPhone window project, there are the following additions; a view controller and accompanying xib, the RestConnection class, and the RestConnectionDelegate protocol.

I'm only going to be talking about the interesting parts of the codes in this article. All that I'm going to say about the app delegate is that it is standard glue code, nothing special going on in there. Lets focus on the RestConnection and it's client, SearchResultsViewController.


RestConnection

RestConnection is a lightweight composition class. It houses an NSURLRequest, NSURLResponse, NSData, and (while loading data) an NSURLConnection. It allows you to specify a base URL string that can be prepended to all requests it handles. It also provides a delegate for callbacks of interesting connection events. Lastly it provides methods for both loading url requests and accessing the current state of the RestConnection; the last request, last response, and last response data.

The method initWithBaseURL is the designated initializer for the class. Calling init will cause this method to be called with an empty base URL. Most of the time when dealing with web services there is a root URL (i.e. domain or ip address) that a collection of services will have in common. The base URL is a convenience for dealing with collections of endpoints so you can easily specify relative URLs in your requests.

Once the class is created, you can set an optional delegate. The delegate will receive callbacks about interesting connection events. All of the information passed to the delegate are accessible via properties as well.

Once a RestConnection instance has been initialized, it can begin requesting data using NSURLRequests with the performRequest method. RestConnection uses NSURLConnection to perform all the requesting. An instance of NSURLConnection is created every time performRequest is executed and destroyed after the request is completed. NSURLConnectionDelegate method callbacks drive the object after this.  The interesting ones are either passed on to the RestConnection delegate or used to accumulate the connection data.

Please note that an instance RestConnection is only meant to retrieve a single resource at a time. Attempting to call performRequest while a request is already pending can have unexpected consequences. A future version of this class will prevent this from being allowed. Creating multiple instances of RestConnection would allow this type of behavior. 


SearchResultsViewController

This view controller drives most the example. First, when the view loads, it creates an instance of the RestConnection and manages it for the lifecycle of the view controller.
- (void)viewDidLoad {
    [super viewDidLoad];
    restConnection = [RestConnection new];
    restConnection.baseURLString = @"http://ajax.googleapis.com/ajax/services/search/";
    restConnection.delegate = self;
}

Here you can note that it instantiates a RestConnection and initializes its properties. The base URL is set which will cause subsequent requests to be relative to that URL string. The delegate is also set to the view controller's instance, this will allow it to keep tabs on the request as the it progresses.

Whenever the user enters something into the search field, the client needs to build a request and retrieve the results. Lets take a look at the method that gets called in the text field's Did End On Exit action.

- (void)performSearchForText:(NSString *)searchText
{
    NSString *text =
        [searchText stringByAddingPercentEscapesUsingEncoding:
        NSASCIIStringEncoding];
    NSString *urlString = [NSString stringWithFormat:@"web?v=1.0&q=%@", text]; 
    [restConnection performRequest:
     [NSURLRequest requestWithURL:
      [NSURL URLWithString:urlString]]];
}

Here the view controller is formatting a URL component with the user's search string and passing it off to the RestConnection to begin loading the data. The data will be loaded asynchronously with delegate callbacks being performed on the same thread from which performRequest was called, in this case the main thread.


RestConnectionDelegate

The protocol RestConnectionDelegate contains 3 methods that are used as callbacks for various phases of loading a URL's contents. This protocol is declared in the interface of the view controller as such:

@interface SearchResultsViewController : UIViewController <RestConnectionDelegate> {

For the example, the delegate methods are used for a few different purposes.

willSendRequest is used to handle showing in the loading UI, a UIActivityIndicator
didReceiveResponse simply logs the response to the console
finishedReceivingData displays the connection's response text and hides the loading UI


Conclusion

This post touched on a lot of different concepts, even though the example's functionality is minimal. Such is life as a developer, a lot of work for very little return. Well not when you consider what is being done under the covers. 

Hopefully this can help you be more productive on your projects. Certainly in future posts the RestConnection class will contain more functionality. We'll even see how we can abstract RestConnection away completely and use the concept of data requests in your client code.

You can find the next post in this series here.

Until the next time, enjoy.


iPhone + EDM + REST

In my first series of posts, i'm going to be talking about my experiences with developing a medical application for the iPhone. This project involved a Microsoft SQL Server database and C# .NET Entity Data Model on the backend and standard native APIs on the mobile device.

I'm going to talk about the challenges me and my coworker faced interfacing a nascent ORM with iPhone technologies. Hopefully someone else will find this information useful in the future.

The first post talks about creating a RestConnection class to facilitate gathering RESTful resources.

Even your worst day has a lesson to learn.