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

    There are currently: 25 Responses to “Developing iOS8 Apps Using Swift – Part 2 – Connect to the iTunes Search API”. Leave your comment!

    Thanks, this works fine.. Keep post tutorials like this….


    In the “Connecting the UI” section, is it assumed that you are using the project from the first tutorial or creating a new view controller and table view? Isn’t the table view already placed inside of the view controller from the previous tutorial?


    Want to understand this. Please enlighten me why absolute iOs Dev newbies (like me) would want to learn Swift now – considering Swift will only be officially released and accepted in the App Store 4-5 months from now?


    Hi, I am still getting an error at the line where it is trying to process the JSON results:

    if jsonResult.count>0 && jsonResult[“results”].count>0 {

    The error says “Thread 1: EXC_BAD_INSTRUCTION” at the exact line above. I copied the code from the example and followed all the steps so I don’t know what could be happening.


      After banging my head around, I discovered that i misspelled “didReceiveResponse” in the connection func declaration. Make sure those connect functions are being called.


    Thanks for this. I’m an AS3 developer so to see 2 methods with the same name is odd ( for me ) eg tableView. Could someone explain please?

    looks like it’s a way to approximate overloading
    http://www.reddit.com/r/swift/comments/27lqpp/does_swift_support_methodconstructor_overloading/


    Thanks so much, I was just about to die due to Flash regret, but I’m inspired to go and create some stuff. OT but I was looking at the FLAPPY BIRDS code in Swift, but couldn’t work out how the project decided which Class was the ‘document’ Class eg the ‘Main’ class the one that kicks it off. Any hints?


    My table is not displaying the images.
    Is anyone having the same issue with me?


    Hello, Very nice Tutorial!!! I see your screenshot and I can see Your tableView doesn’t overlap status bar. MyTable view is overlapping status bar :( How can avoid that? Tks


    Hello, Very nice Tutorial!!! I see your screenshot and I can see Your tableView doesn’t overlap status bar. MyTable view is overlapping status bar :( How can avoid that? Tks


    Hello, Very nice Tutorial!!! I see your screenshot and I can see Your tableView doesn’t overlap status bar. MyTable view is overlapping status bar :( How can avoid that? Tks


    Great Tutorial!!!! By the way… I look at the screen You shared, and TableView is not overlaping status bar… How did You do that?


    Hey, I can’t seem to get this to work. Maybe I missed a step.

    Search iTunes API at URL https://itunes.apple.com/search?term=Angry+Birds&media=software

    fatal error: Can’t unwrap Optional.None

    Program ended with exit code: 9(lldb)

    I get that in the console.


      Hey, you ned to connect the Table view to the appsTableView that has been declared in the view controller. So in the storyboard, just cntrl+drag from viewController to the table view and you will see the appsTableView and view displayed there. Just select the appsTableView to connect UITableView. As the app cannot find this connection it gives a runtime error.


      Not really enough information to know what’s wrong. Something isn’t defined somewhere, but I would have to see your code.


        Srinivas’ reply works. I only connected the Table View to the controller the one way. Didn’t do it the other way. :)


    In my case, I can’t connect the tableview to the appsTableView outlet variable. It doesn’t show up after ctrl+click+drag. The code file itself is saved.


      I had the same problem at first, try doing the opposite (drag from the view controller to the table view)
      That was the only way I could get it to work


        Yeah, this tutorial is missing something I think.

        At line `self.appsTableView.reloadData()`, I got “fatal error: Can’t unwrap Optional.None”, because [email protected] var appsTableView : UITableView` was nil.

        Thanks to pluddy’s trick, it worked.


    You can println(appsTableView) in viewDidLoad to see if it’s connected for sure. And make sure you implement the cell’s delegate methods!


      Love these Swift posts! FYI, I was able to run the Part 2 app without including UITableViewDataSource, UITableViewDelegate in the class definition.


    Why you use storyboards rather than writing UI in code? May be you are doing this faster?


      Storyboards make development faster, and they’re actually quite good. Some purists write all their UI in Obj-C (or in this case swift), but I’ve usually only done that if I have a custom view or something that actually needs it.


    Leave a Reply

    Would you like to sign up to the mailing list by our sister site: SwiftMonthly?