Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsing image from iTunes using JSON to tableviewcontroller

Tags:

ios

swift

I'm trying to parse data from this data source, Titles are parsed correctly and displayed, but the problem occurred when parsing the images, I got an error: “fatal error: unexpectedly found nil while unwrapping an Optional value” Here is my Code:

ViewModel.swift

import Foundation

class ViewModel {

let urlString = "http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/ws/RSS/topsongs/limit=30/json"

var titles = [String]()

var images = [String]()



func fetchTitles(success:() -> ()) {

    let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())

    let url = NSURL(string: urlString)

    let task = session.dataTaskWithURL(url!) { (data, response, error) -> Void in

        let parser = JSONParser()

        self.titles = parser.titlesFromJSON(data!)

        success()

    }

    task.resume()

}

func fetchImages(success:() -> ()) {
    let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())

    let url = NSURL(string: urlString)

    let task = session.dataTaskWithURL(url!) { (data, response, error) -> Void in

        let parser = JSONParser()
        self.images = parser.imagesFromJSON(data!)
        success()
    }
    task.resume()
}

func numberOfSections() -> Int {
    return 1
} 

func numberOfItemsInSection(section: Int) -> Int {
    return titles.count
}

func titleForItemAtIndexPath(indexPath: NSIndexPath) -> String {
    return titles[indexPath.row]
}  

}

and MyTableViewController.swift

import UIKit

class MyTableViewController: UITableViewController {

let viewModel = ViewModel()

var imageCache = [String:UIImage]()



override func viewDidLoad() {

    super.viewDidLoad()

    self.refresh()

    self.refreshControl = UIRefreshControl()

    self.refreshControl?.addTarget(self, action: #selector(MyTableViewController.refresh), forControlEvents: .ValueChanged)



}



func refresh() {

    viewModel.fetchTitles {

        dispatch_async(dispatch_get_main_queue()) {

            self.tableView.reloadData()

            self.refreshControl?.endRefreshing()

        }

    }

    viewModel.fetchImages {

        dispatch_async(dispatch_get_main_queue()) {

            self.tableView.reloadData()

            self.refreshControl?.endRefreshing()

        }

    }



}



override func numberOfSectionsInTableView(tableView: UITableView) -> Int {

    return self.viewModel.numberOfSections()

}



override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    return self.viewModel.numberOfItemsInSection(section)

}



override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! MyTableViewCell

    cell.songTitle.text = self.viewModel.titleForItemAtIndexPath(indexPath)




    let urlString = self.viewModel.titleForItemAtIndexPath(indexPath)

    //found nil 

    let imgURL: NSURL = NSURL(string: urlString)!

    let request: NSURLRequest = NSURLRequest(URL: imgURL)

    NSURLConnection.sendAsynchronousRequest(

        request, queue: NSOperationQueue.mainQueue(),

        completionHandler: {(response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in

            if error == nil {

                cell.songImage.image = UIImage(data: data!)
            }

    })

    return cell

}

and JSONParser.swift

import Foundation

class JSONParser {



func titlesFromJSON(data: NSData) -> [String] {

    var titles = [String]()



    do {

        if let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String: AnyObject],

            let feed = json["feed"] as? [String: AnyObject],

            entries = feed["entry"] as? [[String: AnyObject]] {



            for entry in entries {

                if let name = entry["im:name"] as? [String: AnyObject],

                    label = name["label"] as? String {

                    titles.append(label)

                }

            }

        }

    } catch {

        print("error parsing JSON: \(error)")

    }



    return titles

}



func imagesFromJSON(data: NSData) -> [String] {

    var images = [String]()



    do {

        if let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String: AnyObject],

            let feed = json["feed"] as? [String: AnyObject],

            entries = feed["entry"] as? [[String: AnyObject]] {



            for entry in entries {

                if let name = entry["im:image"]![0] as? [String: AnyObject],

                    label = name["label"] as? String {

                    images.append(label)

                }

            }

        }

    } catch {

        print("error parsing JSON: \(error)")

    }

    return images
}

}

And I have a class MyTableViewCell subclass of UITableViewCell containing a UILabel and a UIImageView. I can't figure out what's the problem, and why I'm getting this error. Thank you for your time.

like image 608
Reem Avatar asked Dec 06 '25 21:12

Reem


1 Answers

I always recommend you to avoid the use of force-unwrapping and adopt a more secure way of code (e.g using optional binding) avoiding runtime errors. So you can change your code to the following code and avoid the runtime error:

for entry in entries {
    if let name = entry["im:image"], let value = name[0] as? [String: AnyObject],
         label = value["label"] as? String {
             images.append(label)
    }
}

In the above way you avoid the use of force-unwrapping.

I hope this help you.

like image 96
Vkt0r Avatar answered Dec 09 '25 13:12

Vkt0r



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!