Saturday, June 18, 2011

Creating a Flickr App Using NSXMLParser, UITableView and SOAP Tutorial

We will create an app that will search photos from flickr, put them in a table view, then display that photo in a webview. We will use SOAP to send our request to flickr. We will receive a corresponding SOAP response, which we will parse with NSXMLParser. There won't be a lot of explanations about the flickr API or about SOAP, I will just be running you through the creation process of this app.













Create a view based application. Name it WebServices. We don't need a nib file for our table view, so dont add one. (I started with the table view, the middle picture, and I didn't create a nib). We would, however need to add two more view controllers later which would need nibs.



Edit WebServicesViewController.h
All we did was to create our model. Anyway lets edit the WebServicesViewController.m

Near the import section add these:

The define statements just creates a macro to show the network activity indicator everytime we send and receive data from the flickr web service. Then we synthesize our model.
Also add these:

































First, get an api key from flickr. You can get one here:http://www.flickr.com/services/api/
When you get your own api key, subsitute it to the blackened out part of the code. We then create our SOAP request in the soapMsg string. Then we create our NSMutableURLRequest. We plug in our url. We also plug in our HTTP header values, set our method to POST, and set our body to soapMsg, which we turn into an NSData by sending it the message "dataUsingEncoding:" .
Then we create a NSURLConnection using the NSMutableURLRequest we just created. 

When we connect to the web service of flickr, a bunch of NSURLConnection methods will be called, so lets implement them.
The "connection: didReceiveResponse:" method gets called as soon as we receive the response from the service. We create an NSData to receive the data we will get from connection: didReceiveData:. We release our NSData object and our connection if we fail in connection: didFailWithError:.
In connectionDidFinishLoading we get our completed NSData *webData and convert it to NSString to clean up the syntax.
This is how the xml file looks before we clean it up.





This is the "after" picture.
















Now lets parse the XML. Lets implement the NSXMLParser methods.
We just parse out the title, server, farm, secret,  photo id. These are stored as attributes, so we "get" them from the attributes dictionary that was passed to us, from the method: parser: didStartElement: namespaceURI qualifiedName: attributes:. We don't do anything in parser foundCharacters, because there is nothing between the photo tags, everything is stored as attributes. Then at parser didEndElement we reload our tableView, which we are about to implement next.


Here we just set our numberOfRowsInSection to the number of entries in the photoTitle array. We also set the cell's textLabel and detailTextLabel to the title and the Id respectively. In didSelectRowAtIndexPath we just pass the contents in one of our model (our arrays) to our detailViewController's properties, which we will be creating next.


But before we do that, make sure our model is released in dealloc.










Ok, now let's create our detailViewController. Go to classes folder, right click, select add new file, UIViewController subclass, don't check "with xib for user interface".
In DetailViewController.h, add these:



















In DetailViewController.m, add these:
























Here we synthesize our model. In loadView, we create a web view that spans the entire screen. We also create method that creates a url string, passing in the parameters of our photo to flickr's server. Then in viewWillAppear we call load our url request that we created in the pictureAddress method. 


We will then have the activity indicator activate while we are loading our photo from flickr. We do this by implementing a couple of methods.
















ShowNetworkActivityIndicator() and HideNetworkActivityIndicator() are just macros we define as:


Then some house keeping at dealloc:
















That takes care of our DetailViewController, now lets create the SearchViewController, the first view of the app. 
Right click the classes folder and add a UIViewController with "Xib for user interface". 
Then add these in the SearchViewController.h:




















Press command b to biuld. Open the SearchViewController.xib, add a UITextField, UIImageView and a UIButton. Arrange them like this:


































imageView image
Download the imageView's image from the link above. Drag and drop the image file into your resources folder in xcode. Make sure to check "copy items into destination folder" checkbox. In interface builder, click the image view, press command 1 to bring up the attributes inspector. In image, select "my_flickr_app.png".


Control drag from the file's owner to the text field, and select searchField. Control drag from the button to the file's owner and select searchBtnClicked:. Save and quit.






























Here we just synthesize our outlet. We also implement our IBAction. We also implement our search method. We just create an instance of WebServicesViewController pass the contents of out searchField's text to the photoSearch property of our WebServicesViewController (the photoSearch property is just inserted into the SOAP xml string request we created in the first part of this tutorial). We then push the instance of WebServicesViewController to our navigation controller's view.
In viewDidLoad, we just declare our class as the delegate of the searchField. This is done so we can implement the textFieldShouldReturn method, where we want the keyboard to disappear after we press the return button. We also want it to call the startSearch method. Then we clean up our outlet in dealloc.

Ok, now lets go to our WebServicesAppDelegate:
Import all the necessary header files. And in application didFinishLaunchingWithOptions, create an instance of SearchViewController. Make it the root view controller of our navigation controller. Give it a title. Then release the svc (after passing it to the navigation controller we dont need it anymore so we release it). Then make sure to add the nvc's view to our window's subview. So that's it! Build and run and enjoy being able to search for photos in flickr using it's SOAP API. :) For questions, hit the comments. 


4 comments:

  1. Hi, I tried the following (part of code):
    NSString *soapMsg = [NSString stringWithFormat:
    @""
    ""
    ""
    "flickr.photos.search"
    "%@"
    "soap"
    "%@"
    "5"
    ""
    ""
    "",apiKey,@"any"];

    And program outputs:

    2011-12-29 15:31:06.484 SimpleTable[4817:207] flickr.photos.searchMyKEYsoapany5
    2011-12-29 15:31:06.922 SimpleTable[4817:207] Done, received bytes: 408
    2011-12-29 15:31:06.923 SimpleTable[4817:207]



    flickr.error.0
    Invalid SOAP envelope.
    http://www.flickr.com/services/soap/
    Please see http://www.flickr.com/services/api/ for more details





    What is wrong with my SOAP :) (Invalid SOAP envelope)?
    And thank You in advance.

    ReplyDelete
  2. I am sorry :), it is impossible to paste the code as an image. I tried to run my application with the same "soapMsg" value (as in your example). But "flickr" returns that my envelope is invalid :(. Could you help me please :)?

    ReplyDelete
  3. I solved it. I typed the content of soapMsg as one string/line. (my question is solved). Thank You :)

    ReplyDelete
  4. Everything Is Working Perfectly, Thank You!

    ReplyDelete