Saturday, May 5, 2012

Build a Web Connected iPhone App. Using the NY Times Best Sellers API

One thing I found difficult to understand when learning Objective-C was how to use Delegates and Protocol's. No matter how many blog posts and tutorials I read I was still struggling to get a firm grasp on how to do it right. So I thought today I could share my experience with you on how to implement a delegate. We will also be covering NSURLConnection and how to use the new json API. We'll create a iPhone app that calls on a web server, downloads some data, then we'll use a delegate to inform our viewController that the download process is done or encountered an error.

We'll be using the NY Times bestsellers API to get a list of the current best selling books.Parse the json and display our results in a tableview. In order to interact with the web service you'll need your own API key. I picked the NY Times because it's very easy to register for a key. You can get yours at http://developer.nytimes.com/.  They have many API's so make sure to check the best sellers when creating a new app. When you get the API Key make sure to copy it somewhere so you have it handy for later use.

OK, Now that you have your API key let's begin by creating a new project in Xcode using the single view template. I'm going to name my project WebSeviceTutorial. You can name yours whatever you want. Be sure to check Use Automatic Reference Counting and Use Storyboards. For Device Family use iPhone.




So, let's create a BestSellers class class. Go to File > New > File, or hit  ⌘N, select objective C class. Then name your class BestSellers, and Subclass of: NSObject. Make sure Targeted for iPad and With XIB user interface are unchecked. Hit next and add it to the project.


OK finally lets add some code. The API returns a list of books with their corresponding details. For this tutorial we're only interested in the Title, Author, Rank, Price, and Description. We also need a way to init our BestSellers class so we'll add an init method also.  So let's add them to our BestSellers class:



Now, we need to synthesize our variables and add the corresponding initializer method to our BestSellers.m :


All we are doing here is checking for self, setting the values passed in from the init method and setting them to our instance variables. Thats all there is to it. Now we have a class to use when we get our results back from the NYT's API.

We need a way to communicate with the NYT's API so it's time to start building our web service class. We'll be repeating the steps that we went through when we created our BestSellers class with the only difference being the name.  Go to File > New > File, or hit  ⌘N, select objective C class. Then name your class MyWebService, and Subclass of: NSObject. Make sure Targeted for iPad and With XIB user interface are unchecked. Hit next and add it to the project.




First thing we need to do is import our BestSellers class in the MyWebService.h so we can use it.
We'll be asking the user to choose which best seller list they want to see, so we need a variable to hold the value of their choice, we'll name it query. We're also going to use a delegate to let our controller know when we are done downloading and parsing the NYT's results, and a NSMutableData object to hold the actual data coming in from the web service. So let's get to it:



Since we're using ARC our delegate is defined a bit differently than you may be used to but it's beyond the scope of this tutorial to get into the reasons for defining the delegate as a weak reference If you want to know more about ARC there's a good post here:http://maniacdev.com/ios-5-sdk-tutorial-and-guide/arc-automatic-reference-counting/. Back to the action, The protocol definition is where we actually create the delegate ,
We give it a name, "MyWebServiceDelegate" in this case.
We then declare the delegate's methods.
We want to know if the web service succeeds and, if for whatever reason, the web service fails. These methods will be used in our controller class to communicate with our MyWebService class. Think of it as a telephone call to any class that adopts this protocol, adopting a protocol really just means it's a listener. In this case MyWebService will be the sender, and our controller, which we haven't created yet, will be the listener.
Next, we need to adopt two protocols, <NSURLConnectionDelegate,NSURLConnectionDataDelegate>
in our MYWebService.h. Which means we'll be listening for their phone calls.


We've also added two methods here:
1. An init method.
2. And a method to start the process of calling the web service.
Pretty self explanatory.

Let's move on the implementation of MyWebService. Be sure to synthesize our query, bestSellerData and the delegate in MyWebService.m.


We also added a #define to the top of our class,  BESTSELLER_URL passing in the URL to the NYT's API. Just replace YOUR_API _KEY with your actual api key. Note that I used the ,%@ in place of the "book-list-name" parameter, so we can add it later based on the user choice.(Fiction, Hardcover etc.). More on this later.

We init our class the same as always, checking for self, and returning self.

In the start method:
We initialize and alloc bestSellerData, getting it ready to use.
It's always good to check if a variable has any value before using it, so that's what we do here with query.
Create a NSURL from our defined BESTSELLER_URL and our query variable. 
Create a NSURLRequest, which we'll then pass to the NSURLConnection. Here we added a time-out interval of 30 seconds so if it takes too long we can respond appropriately. I always do this because web services are unpredictable. It's just one of those things that can make the user experience better. It's up to you how to handle it. We'll decide a little later on how to deal with Errors.
All thats left to do is start the connection.


Let's now implement those NSURLConnection delegate methods.
The three methods are:




We add the incoming data to our bestSellerData object in the didRecieveData: method.
Then we use our MyWebServiceDelegate error method to pass the error, if it occurs, to whoever is listening.
Next we will get the finished downloaded data an parse it into something useable.



There's a lot here so let's go over it:
First we check bestSellerData to see if it's got a value.
Create a NSMutableArray to hold our objects later.
Next, we're using the new iOS 5 json API to get the json data. We pass in our bestSellerData and an error to the the NSJSONSerialization method, which will take the data and convert it to a json dictionary for us.
Now that we have our json from the NYT's we need to begin parsing it. It's chock full of information. We're mostly interested in the results node which is an array of best seller objects.
 We loop through each object and pull out the the relevant information. You can look at the json structure by using an NSLog(@"JSON",json) right after we create the json dictionary.
 Each object in the loop contains:
A Dictionary of book-details with the title, description, author and price.
The rank is not in the book-details node, but in the results node so we grab it there in the loop.

Notice that I've made our BestSellers class so it accepts all strings for easier use later. Now that we have all the details we want in NSString format we can alloc and init an instance of our BestSellers class and pass in the all of the values Title, Price, Rank, Description, Author and Price.
Add the bestSellers object to the bookDetailsArray we created earlier in this method. The loop will continue until it's done with all the entries in the json dictionary.
 When the loop finishes we use our delegate to send the bookDetailsArray to whoever is listening.
The MyWebService.m should look like this:


 That's it for now, In the next post We'll Create the user interface using storyboards, create our ViewControllers and learn how to use a custom UITableViewCell.
Stay tuned!













No comments:

Post a Comment