Show Menu

Looking to hire an app developer?

Submit your 30 day Job Listing for FREE

This tutorial shows you how to connect to the iTunes Search API using Swift for iOS8.

This article is part of the create iOS8 Applications with Swift tutorial series, here are the other published articles:

    In the first tutorial, creating iOS8 Applications with Swift we went over some basics of Swift, and set up a simple example project that creates a Table View and a puts some text inside of them. If you haven’t read that yet, give it a read with the link above.

    For this article, we’re going to do something a little more ambitious. We’re going to hit the iTunes Search API using iOS8 Swift for the iTunes Store, download the JSON results, parse them in to Dictionaries and then populate our Table View with this information. Then, we will add some user interaction by adding a click event to the tableview, so that when an item is clicked the iTunes store item will be opened.

    If this sounds like a lot of work, don’t sweat it. This is pretty basic functionality for iOS apps and it’s one of the most common things any developer has to do. Let’s get going…

    Connecting the UI

    The first thing we need to do is get a reference to our tableView, so it can be used from code. Go ahead and add this line to your ViewController.swift file, just under the class definition, but outside of any functions.

    
    @IBOutlet var appsTableView : UITableView
    

    This bit of code allows you to connect to our Table View in our Storyboard to this variable, “appsTableView”. Save this file and open up your storyboard. Now by control+click+dragging from the Table View to our ‘View Controller’ object, we’ve linked these objects. Easy, right?

    Making the API Request

    Now that we have the UI connected, we’re ready to make an API call. Create a new function called searchItunesFor(searchTerm: String). We’ll use this to make our requests happen for arbitrary search terms.

    To keep this iOS8 tutorial short, I’m going to just post my final code and let the comments do some of the explaining. I’m always open to questions and further discussion in the comments though, so feel free to chime in!

    
    
       func searchItunesFor(searchTerm: String) {
    
       // The iTunes API wants multiple terms separated by + symbols, so replace spaces with + signs
       var itunesSearchTerm = searchTerm.stringByReplacingOccurrencesOfString(" ", withString: "+", options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil)
    
       // Now escape anything else that isn't URL-friendly
       var escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
       var urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=software"
       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()
    }
    

    Let’s go line-by-line.

    First, we need to do some fixing of the search terms we pass in, the iTunes Search API wants terms in the form of “First+Second+Third+Words” rather than “First%20Second%20…” etc. So instead of URL-encoding, we use an NSString method called stringByReplacingOccurencesOfString. This returns a modified versions of the searchTerm variable with all our spaces replaced with + symbols.

    Next, we actually escape the search term in case of an other symbols that won’t fit in a URL. The next 2 lines define an NSURL object that can be used as a Request URL for iOS8’s networking API.

    These two lines are critical:

    
    var request: NSURLRequest = NSURLRequest(URL: url)
    var connection: NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: false)
    

    The first creates an NSURLRequest object with our target URL being the url variable we created above. The second line then creates the *connection* which is going to be used to actually send the request. Notice in the parameters we set the delegate to self. This allows us to listen in on resultant information coming from the connection inside of our View Controller class.

    Finally, connection.start() actually begins the request.

    Preparing for the response

    Now we’ve got a method that starts an iTunes Search API response when we call it. So let’s insert the following at the end of viewDidLoad

    
    searchItunesFor("JQ Software")
    

    This will find any software products on the iTunes store containing that phrase, which in this case will include a couple of games I made years ago, and a few more recent things. Feel free to change the search string to whatever you like.

    Now to actually receive the response we need to keep track of a data object which will contain the results. So first let’s add an instance of NSMutableData as a member of our class, do this by inserting the following line just below the class definition, inside of the curly braces. While we’re at it, let’s also create an array to hold our table info.

    
    var data: NSMutableData = NSMutableData()
    var tableData: NSArray = NSArray()
    

    Now, let’s incorporate the functions that NSURLConnection will be sending our class, since it is the delegate of our request we can expect any information from NSURLConnection to be sent back through it’s protocol methods, defined in NSURLConnectionDataDelegate and NSURLConnectionDelegate. If you don’t know what that means, that’s okay. Let’s just proceed and you’ll see how it works.

    Receiving the response

    Now we’re going to add the biggest chunk of iOS 8 Swift code so far, which is still not much code, to handle the entirety of the resulting information:

    
    func connection(didReceiveResponse: NSURLConnection!, didReceiveResponse response: NSURLResponse!) {
       // Recieved a new request, clear out the data object
       self.data = NSMutableData()
    }
    
    func connection(connection: NSURLConnection!, didReceiveData data: NSData!) {
       // Append the recieved chunk of data to our data object
       self.data.appendData(data)
    }
    
    func connectionDidFinishLoading(connection: NSURLConnection!) {
       // Request complete, self.data should now hold the resulting info
       // Convert the retrieved data in to an object through JSON deserialization
       var err: NSError
       var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options:    NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
    
       if jsonResult.count>0 && jsonResult["results"].count>0 {
          var results: NSArray = jsonResult["results"] as NSArray
          self.tableData = results
          self.appsTableView.reloadData()
    
       }
    }
    

    When NSURLConnection receives a response, we can expect the didReceiveResponse method to be called on our behalf. At this point we simply reset our data by saying self.data = NSMutableData(), creating a new empty Data object.

    After a connection is made, we will start receiving data in the method didReceiveData. The data argument being passed in here is where all our juicy information comes from. We need to hold on to each chunk that comes in, so we append it to the self.data object we cleared out earlier. Finally when the connection is done and all data has been received, connectionDidFinishLoading is called and we’re ready to use the data in our app. Hooray!

    The connectionDidFinishLoading method here uses the NSJSONSerialization class to convert our raw data in to useful Dictionary objects by deserializing the results from iTunes.

    Now, because we know the rough layout of the data coming back from iTunes Search API, a simple check on the count of the “results” key is enough to validate that we did in fact get back the data we were expecting, so we can now set our self.tableData object to be the resulting data, and tell the appsTableView to reload it’s content. This will cause the Table View object to run it’s own delegate methods. Defining these is the final step in our iOS8 Swift Connect to the iTunes Search API tutorial.

    Updating the Table View UI

    You may remember from last time we implemented two function for our Table View. A count function, which determines the number of rows; and a cell function, which actually creates the cell and modifies it for each row.

    We’re going to update these now to use the data we pulled down from the web.

    Swap out your methods with these two functions:

    
        func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
           return tableData.count
        }
    
       func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
       let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell")
    
       var rowData: NSDictionary = self.tableData[indexPath.row] as NSDictionary
    
       cell.text = rowData["trackName"] as String
    
       // Grab the artworkUrl60 key to get an image URL for the app's thumbnail
       var urlString: NSString = rowData["artworkUrl60"] as NSString
       var imgURL: NSURL = NSURL(string: urlString)
    
       // Download an NSData representation of the image at the URL
       var imgData: NSData = NSData(contentsOfURL: imgURL)
       cell.image = UIImage(data: imgData)
    
       // Get the formatted price string for display in the subtitle
       var formattedPrice: NSString = rowData["formattedPrice"] as NSString
    
       cell.detailTextLabel.text = formattedPrice
    
       return cell
    }
    

    The numberOfRowsInSection is now simply returning the number of resultant objects from the tableData member, which is set in our prior connectionDidFinishLoading method.

    The cellForRowAtIndexPath is also not changed dramatically in this case. Rather than simply returning the row number, we use the row number to grab three pieces of information: the track name, the artwork url, and the price. Using these keys we construct the title, subtitle, and an image to go along with the cell.

    Full ViewController.swift file:

    
    //
    //  ViewController.swift
    //  TestSwift
    //
    //  Created by Jameson Quave on 6/2/14.
    //  Copyright (c) 2014 JQ Software LLC. All rights reserved.
    //
     
    import UIKit
     
    class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, NSURLConnectionDelegate, NSURLConnectionDataDelegate {
        
        @IBOutlet var appsTableView : UITableView
        var data: NSMutableData = NSMutableData()
        var tableData: NSArray = NSArray()
                                
        override func viewDidLoad() {
            super.viewDidLoad()
            searchItunesFor("Angry Birds");
        }
        
        func searchItunesFor(searchTerm: String) {
            
            // The iTunes API wants multiple terms separated by + symbols, so replace spaces with + signs
            var itunesSearchTerm = searchTerm.stringByReplacingOccurrencesOfString(" ", withString: "+", options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil)
            
            // Now escape anything else that isn't URL-friendly
            var escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
            var urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=software"
            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()
        }
        
        func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
            return tableData.count
        }
        
        
        func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
            let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell")
            
            var rowData: NSDictionary = self.tableData[indexPath.row] as NSDictionary
            
            cell.text = rowData["trackName"] as String
            
            // Grab the artworkUrl60 key to get an image URL for the app's thumbnail
            var urlString: NSString = rowData["artworkUrl60"] as NSString
            var imgURL: NSURL = NSURL(string: urlString)
            
            // Download an NSData representation of the image at the URL
            var imgData: NSData = NSData(contentsOfURL: imgURL)
            cell.image = UIImage(data: imgData)
            
            // Get the formatted price string for display in the subtitle
            var formattedPrice: NSString = rowData["formattedPrice"] as NSString
     
            cell.detailTextLabel.text = formattedPrice
            
            return cell
        }
        
        
        func connection(connection: NSURLConnection!, didFailWithError error: NSError!) {
            println("Connection failed.\(error.localizedDescription)")
        }
        
        func connection(connection: NSURLConnection, didRecieveResponse response: NSURLResponse)  {
            println("Recieved response")
        }
        
        
        
        
     
        
        func connection(didReceiveResponse: NSURLConnection!, didReceiveResponse response: NSURLResponse!) {
            // Recieved a new request, clear out the data object
            self.data = NSMutableData()
        }
        
        func connection(connection: NSURLConnection!, didReceiveData data: NSData!) {
            // Append the recieved chunk of data to our data object
            self.data.appendData(data)
        }
        
        func connectionDidFinishLoading(connection: NSURLConnection!) {
            // Request complete, self.data should now hold the resulting info
            // Convert it to a string
            var dataAsString: NSString = NSString(data: self.data, encoding: NSUTF8StringEncoding)
            
            // Convert the retrieved data in to an object through JSON deserialization
            var err: NSError
            var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
            
            if jsonResult.count>0 && jsonResult["results"].count>0 {
                var results: NSArray = jsonResult["results"] as NSArray
                self.tableData = results
                self.appsTableView.reloadData()
                
            }
            
        }
        
    }
    

    Try running our iOS8 Swift app, and you’ll see we for the first time have created something that actually looks like an app all in Swift! A quick search for Angry Birds gives me the following screen:

    iOS8 AngryBirds Swift iTunes Search Api Results

    Next time in Part 3 we’ll work on the interaction piece of the app, allowing users to search for anything they like, and making the table cells clickable!

    having issues?

    We have a Questions and Answer section where you can ask your iOS Development questions to thousands of iOS Developers.

    Ask Question

    FREE Download!

    Get your FREE Swift 2 Cheat Sheet and quick reference guide PDF download when you sign up to SwiftMonthly


    Sharing is caring

    If you enjoyed this tutorial, please help us and others by sharing using one of the social media buttons below.


    Written by:

    I am an app developer in Austin, TX. I spend time dabbling with iPhone, iPad, Android, and web technologies. I write about technology, startups, and my technology & entrepreneurial experiments. More of my Swift Tutorials can be found on my site.

    Comments

    comments