使用Swift解析JSON

Mar*_*ers -1 parsing json tableview ios swift

我在自定义类中有一个异步方法,它返回一个包含字典的NSArray.我试图在UITableView中显示这些数据.一个问题是getGenres方法调用是异步的,因此在显示表之后会加载数据.主要问题是弄清楚如何实现3种数据源方法.在Objective C中,这很简单......

var genreList:NSArray?

override func viewDidLoad() {
    super.viewDidLoad()
    Bookshop.getGenres {
        genres in
            self.genreList = genres // copies data to the public NSArray
            self.tableView.reloadData() // this returns the data async so need to reload the tableview
            println("records: \(self.genreList?.count)") // displays the array of dictionaries correctly
    }
}

// #pragma mark - Table view data source

override func numberOfSectionsInTableView(tableView: UITableView!) -> Int {
    return 1
}

override func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
    if self.genreList != nil {
        println("Rows in section: \(self.genreList?.objectAtIndex(0))")
        return self.genreList?.count! // Value of optional 'Int?' not wrapped; did you mean to use '!' 
    }
    return 3
}

override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell? {
    let cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier("GenreCell", forIndexPath: indexPath) as UITableViewCell
    cell.textLabel.text = "Hello World!"
    println("ROW: \(indexPath.row)")
    println("data: \(self.genreList?.objectAtIndex(indexPath.row))")
    var item = self.genreList?.objectAtIndex(indexPath.row) Variable 'item' inferred to have type 'AnyObject?', which may be unexpected.
    //cell.textLabel.text = item.title
    //var item:NSDictionary = self.genreList?.objectAtIndex(indexPath.row) as NSDictionary
    //println("item: \(item)")
    return cell
}
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?做一个非常简单的任务似乎是不必要的复杂.

这是我的实用程序类:

import Foundation

class Bookshop {
    class func getGenres(completionHandler: (genres: NSArray) -> ()) {
        //println("Hello inside getGenres")
        let urlPath = "http://creative.coventry.ac.uk/~bookshop/v1.1/index.php/genre/list"
        //println(urlPath)
        let url: NSURL = NSURL(string: urlPath)
        let session = NSURLSession.sharedSession()
        var resultsArray:NSArray!
        let task = session.dataTaskWithURL(url) {
            data, response, error in
            //println("Task completed")
            if(error) {
                println(error.localizedDescription)
            }
            //println("no error")
            var err: NSError?
            var options:NSJSONReadingOptions = NSJSONReadingOptions.MutableContainers
            var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: options, error: &err) as NSDictionary
            if(err != nil) {
                println("JSON Error \(err!.localizedDescription)")
            }
            //NSLog("jsonResults %@", jsonResult)
            let results: NSArray = jsonResult["genres"] as NSArray
            //NSLog("jsonResults %@", results)
            //resultsArray = results
            //println("calling completion handler")
            completionHandler(genres: results)
        }
        task.resume()
    }
}
Run Code Online (Sandbox Code Playgroud)

Dav*_*rry 5

快速做的只是消除了一堆我们真的不应该依赖的容易出错的功能,特别是依赖于设置为零的消息总是容易出错.现在它有点冗长,但更明确,因此更安全.

return self.genreList.count在Objective-C中的等价物是:

override func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
    if let genres = self.genreList {
        return genres.count
    }
    else {
        // Note: this is the case when you haven't yet downloaded your genre
        //  list, do whatever is appropriate, this just shows an empty list
        return 0
    }
}
Run Code Online (Sandbox Code Playgroud)

由于cellForRowAtIndexPath只有在非零单元数的情况下才会调用,因此该方法更简单,但实际上为了一致性/安全性,您遵循相同的一般流程:

override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell? {
    if let genres = self.genreList as? [NSDictionary] {
        let cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier("GenreCell", forIndexPath: indexPath) as UITableViewCell
        var item = genres[indexPath.row]
        cell.textLabel.text = item["title"] as String
        return cell
    }
    else {
        // Note: again, this is the case where you don't have your genre list
        //  list yet, so you can create whatever default cells needed.
        return nil
    }
}
Run Code Online (Sandbox Code Playgroud)