Showing posts with label Service. Show all posts
Showing posts with label Service. Show all posts

Monday, June 9, 2014

Access REST Web Service with Apple’s new Swift Language

In Apple’s own words, “Swift is an innovative new programming language for Cocoa and Cocoa Touch”.  From what I have seen so far I would agree with Apple’s description.  In this post I will show how easy it is to access a REST based Web Service with Swift by writing a simple iTunes search API.

So lets get started.  You will need XCode beta 6 to work with Swift so if you have not already downloaded/installed it you will need to do so now.   Once you have XCode 6 beta on your machine, start a new project and select the Single View Application template.


On the next option screen, enter the name of your project and then select Swift as the language.



Finally select the location of your project and now you are ready to start. 

We will begin by creating a ITunesSearchAPI class that will be used to make requests to Apple’s iTunes search API.  In this class we will define a Protocol that will be used to return the results of our search.  Lets start by defining our protocol:

protocol ITunesSearchAPIProtocol {
    func didRecieveResponse(results: NSDictionary)
}

The ITunesSearchAPIProtocol contains one function.  This function will receive an NSDictionary object that contains the results of our request to iTunes.

Now lets start the ITunesSearchAPI class.  We will start off by defining two properties like this

class ITunesSearchAPI: NSObject {
    var data: NSMutableData = NSMutableData()
    var delegate: ITunesSearchAPIProtocol?
}

These properties are the data property used to store the data coming back from the server and the delegate property that is used to define our ITunesSearchAPIProtocol.  Now lets create a searchItunesFor function that we will call to perform our search (Note this code has been updated for Swift 1.2, I have noted where changes were made form the original code).

func searchItunesFor(searchTerm: String) {
        
        //Clean up the search terms by replacing spaces with +
        var itunesSearchTerm = searchTerm.stringByReplacingOccurrencesOfString(" ",withString: "+", options: NSStringCompareOptions.CaseInsensitiveSearch,range: nil)
        
        // Changed for Swift 1.2
        // var escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
        if let escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) {
            
            var urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=music"
            
            // Changed with Swift 1.2
            //  var url: NSURL = NSURL(string: urlPath)
            if let url = NSURL(string: urlPath) {
                var request: NSURLRequest = NSURLRequest(URL: url)
                
                //changed with Swift 1.2
                //  var connection: NSURLConnection = NSURLConnection(request: request,delegate: self,startImmediately: false)
                if let connection = NSURLConnection(request: request,delegate: self,startImmediately: false) {
                    
                    println("Search iTunes API at URL \(url)")
                    
                    connection.start()
                }
            }
        }

    }

The first two lines clean up the search term string that was passed into the searchItunesFor function so it can be used to create our search URL.  We then use this URL to create a NSURL object.  That NSURL object is used to create an NSURLRequest object and finally the NSURLRequest is used to create a NSURLConnection object.  Notice we set the startImmediately parameter, of the NSURLConnection, to false, this prevents the request from starting immediately.  If there is no additional code needed, you can set this to True to make the request run immediately but I like setting it to false and manually starting the connection.  This allows me to initialize anything needed prior to the request being made.  The last line is what manually starts the NSURLConnection.

Now lets create the NSURLConnectionDataDelegate functions.  Here is the first function which is called if the connection fails:

    //NSURLConnection Connection failed
    func connection(connection: NSURLConnection!, didFailWithError error: NSError!) {
        println("Failed with error:\(error.localizedDescription)")
    }

This next function is called when a new connection is established.  In this function we simply clear the data property.

    //New request so we need to clear the data object
    func connection(didReceiveResponse: NSURLConnection!, didReceiveResponse response:NSURLResponse!) {
        self.data = NSMutableData()
    }
   
This function is called each time data is received from the server.  In this function we append the new data to our data property.

    //Append incoming data
    func connection(connection: NSURLConnection!, didReceiveData data: NSData!) {
         self.data.appendData(data)
    }

This last function is called after all information is received from the server.  In this function we convert the data received from the server to a NSDictionary object.  We then call the delegate’s didReceiveResponse function with the NSDictionay object.  (Note this code has been updated for Swift 1.2, I have noted where changes were made form the original code)
   
    //NSURLConnection delegate function
    func connectionDidFinishLoading(connection: NSURLConnection!) {
        //Finished receiving data and convert it to a JSON object

        //Changed with Swift 1.2
        // var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data,options:NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
        var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data,options:NSJSONReadingOptions.MutableContainers, error: nil) as! NSDictionary
        
        delegate?.didRecieveResponse(jsonResult)
    }


Now lets look at how we would use the ITunesSearchAPI class.  The first thing we need to do is to add the ITunesSearchAPIProtocol to the list of protocols that the ViewController adopts.  To do this, simply add the ITunesSearchAPIProtocol to the comma-separated list following the name of the class’s super class like this: 

class ViewController: UIViewController, ITunesSearchAPIProtocol

In the apps ViewController.swift file add one property like this:

var api: ITunesSearchAPI = ITunesSearchAPI()

This will set the api property to our ITunesSearchAPI type and initiate it.   We then want to add the following two lines to the viewDidLoad function.

api.delegate = self;
api.searchItunesFor("Jimmy Buffett")

These two lines sets the delegate of our api property to this object and then calls the searchItunesFor function passing it the string “Jimmy Buffett” as the search term. 

Finally add our delegate function like this:

func didRecieveResponse(results: NSDictionary) {
    println(results)
}

This function simply logs the response to the console.  In future posts we will expand this function to actually do something with the data.

The full ITunesSearchAPI.swift file should look like this:


import UIKit

protocol ITunesSearchAPIProtocol {
    func didRecieveResponse(results: NSDictionary)
}

class ITunesSearchAPI: NSObject {
    var data: NSMutableData = NSMutableData()
    var delegate: ITunesSearchAPIProtocol?
   
    //Search iTunes
    func searchItunesFor(searchTerm: String) {
       
        //Clean up the search terms by replacing spaces with +
        var itunesSearchTerm = searchTerm.stringByReplacingOccurrencesOfString(" ", withString: "+",
                          options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil)
       
        var escapedSearchTerm =                         itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
        var urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=music"
        var url: NSURL = NSURL(string: urlPath)
        var request: NSURLRequest = NSURLRequest(URL: url)
        var connection: NSURLConnection = NSURLConnection(request: request, delegate: self,
                          startImmediately: false)
       
        println("Search iTunes API at URL \(url)")
       
        connection.start()
    }
   
    //NSURLConnection delegate method
    func connection(connection: NSURLConnection!, didFailWithError error: NSError!) {
        println("Failed with error:\(error.localizedDescription)")
    }

    //NSURLConnection delegate method
    func connection(didReceiveResponse: NSURLConnection!, didReceiveResponse response: NSURLResponse!) {
        //New request so we need to clear the data object
        self.data = NSMutableData()
    }
   
    //NSURLConnection delegate method
    func connection(connection: NSURLConnection!, didReceiveData data: NSData!) {
        //Append incoming data
        self.data.appendData(data)
    }
   
    //NSURLConnection delegate method
    func connectionDidFinishLoading(connection: NSURLConnection!) {
        //Finished receiving data and convert it to a JSON object
        var err: NSError
        var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data,
                          options:NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary

        delegate?.didRecieveResponse(jsonResult)
    }

}


The full ViewController.swift file should look like this:

import UIKit

class ViewController: UIViewController, ITunesSearchAPIProtocol{
   
    var api: ITunesSearchAPI = ITunesSearchAPI()
   
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
       
        api.delegate = self;
        api.searchItunesFor("Jimmy Buffett")
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func didRecieveResponse(results: NSDictionary) {
        // Store the results in our table data array
        println(results)
    }

}


Part 2:  In part 2 we will expand on the code presented here to display the results, with album covers, in a UITableView.  We will have two requirements for loading images, they must be loaded in the background so the UI does not freeze while the images load and to create an image cache so we do not reload images we already have. To read part 2, follow this link Access REST Web Service with Apple’s new Swift Language - Part 2