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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With