使用 Alamofire 响应填充表视图

Posted

技术标签:

【中文标题】使用 Alamofire 响应填充表视图【英文标题】:Populating table view with Alamofire response 【发布时间】:2016-06-20 20:35:08 【问题描述】:

我正在尝试使用 Alamofire 获得的响应填充我的 UITableView。 JSON 的 URL 是 https://api.themoviedb.org/3/movie/now_playing?api_key=a07e22bc18f5cb106bfe4cc1f83ad8ed。我只需要这个 JSON 中的 response.result.value["results"] 字典数组。 我没有问题,但是当我尝试在 Alamofire 之外打印它时,请求为空,并且我的单元格无法填充此数据,因为单元格数为 0。 我在主线程中尝试了 tableView.reloadData(),正如这里所说的 Populating Table Cells With Alamofire Data,但这没有产生积极的结果。你认为我做错了什么?我委托了表格视图并更新了框架,一切都应该正常工作。

这里是一段代码:

func retrieveRecentEntries() 
    let url = "https://api.themoviedb.org/3/movie/now_playing?api_key=a07e22bc18f5cb106bfe4cc1f83ad8ed"

    Alamofire.request(.GET, url, parameters: [:], encoding: .JSON, headers: [:]).responseJSON  (response) in
        self.entries = (response.result.value!["results"] as? [NSDictionary])!

        dispatch_async(dispatch_get_main_queue()) 
            print("OO")
            print("Entries1: \(self.entries)")//giving JSON


            self.tableView.reloadData()
        
    

    print("Entries2: \(self.entries)")//empty


UITableView 委托方法:

   func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    //Sort entries by date and return amount of entries for each date section
    return entries.count ?? 0


func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCellWithIdentifier("entryCell", forIndexPath: indexPath) as! EntryCell

    //Populate each indexPath.row with one entry
    let entryDict = entries[indexPath.row]

    let dateString = entryDict["release_date"] as! String
    formatter.dateFormat = "yyyy-MM-dd"

    let dateDate = formatter.dateFromString(dateString)
    formatter.dateFormat = "MMMM d, yyyy"

    let dateStr = formatter.stringFromDate(dateDate!)

    //Store entry details to show them as labels
    let projectName = entryDict["title"] as! String
    let description = entryDict["overview"] as! String
    let task = entryDict["original_title"] as! String
    let hours = entryDict["vote_average"] as! Double

    //Show cell labels
    cell.projectNameLabel.text = projectName
    cell.dateLabel.text = dateStr
    cell.taskLabel.text = task
    cell.descriptionLabel.text = description
    cell.hoursLabel.text = String(format: "%.2f", hours)

    print("HERE")//this isn't printed
    return cell

【问题讨论】:

【参考方案1】:

Jack 说您的行 print("Entries2: \(self.entries)") 为空是正确的,因为它是在发送 Alamofire 请求后立即执行的。 将您的 self.entries 分配放在您的 dispatch_async 中应该不会有什么不同,但值得一试。

您提到您已正确设置您的delegate。你也设置了dataSource吗?

你在哪里打电话retrieveRecentEntries()


关于它们的价值的一些建议。

虽然使用NSDictionary 会起作用,但它来自Objective-C. 而不是[NSDictionary],我建议使用更“快速”的方法并使用[String : AnyObject].

还有很多情况下,你隐含的unwrapping 你的optionals。如果您知道这些值永远不会是nil.,这没关系,但由于您解包的值来自服务器,因此最好处理这些值是nil. 的可能性,因为如果它们是,而你隐含地解开它们,你的应用就会崩溃。 我建议更新您的代码以使其更安全并执行以下操作。

func retrieveRecentEntries() 
    let url = "https://api.themoviedb.org/3/movie/now_playing?api_key=a07e22bc18f5cb106bfe4cc1f83ad8ed"

    Alamofire.request(.GET, url, parameters: [:], encoding: .JSON, headers: [:]).responseJSON  (response) in

        guard let validResponse = response.result.value as? [String : AnyObject], validEntries = validResponse["results"] as? [String: AnyObject] else 
            return
        

        // Now you can assign validEntries to self.entries because you know it is not nil
        self.entries = validEntries

        dispatch_async(dispatch_get_main_queue()) 
            print("OO")
            print("Entries1: \(self.entries)")//giving JSON
            self.tableView.reloadData()
        
    

我还将更新您的cellForRowAtIndexPath 中的所有位置,您在这些位置隐式地从entryDict 解包值。只要这些值中的任何一个为零,您的应用就会崩溃。如果您还不熟悉它,我会checkout Swift 的guard statement。

【讨论】:

嘿,尽管它没有解决我的问题,但感谢guard,我发现它非常有益,而不是在这里使用if ... else ... 不客气!我很高兴您能够解决您的问题。 ?【参考方案2】:

当你打印 Entries2 时,数组是空的,因为该代码是在 alamofire 请求发送后立即执行的,所以还没有收到响应。

可能发生的情况是,当您调用 reloadData() 时,条目不会更新。尝试移动

self.entries = (response.result.value!["results"] as? [NSDictionary])!

到 dispatch_async 块内。

【讨论】:

【参考方案3】:

这个问题都是关于编码的。我将参数编码为 .JSON,这对于 .GET 函数不是必需的。应该是

Alamofire.request(.GET, url, parameters: [:], encoding: .URL, headers: [:]).responseJSON  (response) in

Alamofire.request(.GET, url, parameters: [:], headers: [:]).responseJSON  (response) in

因为使用 URL 进行编码是默认设置。代码是正确的,是的,我使用guard 安全地解包接收到的数据。

【讨论】:

【参考方案4】:

顺便说一句,在 Alamofire 3 (Swift 2.3) 中,response.result.value 在失败的情况下为零,所以你不能再使用它了:

guard let validResponse = response.result.value as? [String : AnyObject], validEntries = validResponse["results"] as? [String: AnyObject] else 
    return

你需要解析数据,因为数据总是返回,不管响应是成功还是失败:

guard let data = response.data,
                    let json = try? NSJSONSerialization.JSONObjectWithData(data, options: []),
                    let responseJSON = json as? [String:AnyObject] else 
    return 

【讨论】:

以上是关于使用 Alamofire 响应填充表视图的主要内容,如果未能解决你的问题,请参考以下文章

将 alamofire json 响应转换为变量

使用 SwiftJSON 将 Alamofire 结果 JSON 加载到表视图中

使用 Alamofire 从 API 获取响应

使用 RxSwift 将 Alamofire 请求绑定到表视图

如何处理 Alamofire 的异步特性 [重复]

如何使用来自 Alamofire 发布请求的 SwiftyJSON 填充下拉列表?