【问题标题】:cellForRow(at: indexPath) returns nil and crashes my swift appcellForRow(at: indexPath) 返回 nil 并使我的 swift 应用程序崩溃
【发布时间】:2017-02-06 20:47:43
【问题描述】:

在我的swift 应用程序中,我在UITableView 中显示单元格,前10 个单元格包含一张照片。我决定为每个单元格添加视差效果,这样当用户上下滚动表格时 - 图像会改变它的偏移量。

这是我从我的网络服务中获取数据并最初将其添加到 tableview 的方式:

func makePostQueryForFetchingData(_ parameters: [String:AnyObject], url: String, type: String)
{
    Alamofire.request(url, method: .post, parameters: (parameters), encoding: JSONEncoding.default)
        .validate()
        .responseJSON { response in

            switch response.result {
            case .success:
                DispatchQueue.main.async(execute: {
                    items.removeAllObjects()
                    tview.reloadData()
                    if let jsonData = response.result.value as? [[String: AnyObject]] {
                        for singleJSON in jsonData {
                            if let single = SingleNode.fromJSON(JSON(singleJSON)){
                                    self.items.add(single)
                            } 
                        }
                    }  
                    self.refreshController.endRefreshing()
                    print("before crash")
                    self.tview.reloadData()
                    print("end")
                })
            case .failure(let error):
               print(error)
            } 
    }
}

当我在启动时运行此功能时 - 一切正常。但是,如果我向下滚动表格,然后快速向上滚动并拉动以刷新 - 应用程序崩溃。

在拉动刷新中,我从上面调用函数。

处理视差效果的函数如下所示:

override func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if (scrollView == self.tview) {
        for indexPath in self.tview.indexPathsForVisibleRows! {
            if (indexPath.row < 10) {
                print(indexPath)
                print(self.tview.cellForRow(at: indexPath))
                self.setCellImageOffset(cell: self.tview.cellForRow(at: indexPath) as! BigDetailsOnListCell, indexPath: indexPath as NSIndexPath)
            }
        }
    }
}

我意识到,当我快速向上滚动表格并刷新它时 - 我在控制台中看到:

before crash
0
nil
fatal error: unexpectedly found nil while unwrapping an Optional value

那么为什么self.tview.cellForRow(at: indexPath) 返回 nil?

【问题讨论】:

  • 请同时放上cellForRow方法的代码
  • cellForRow(at:) 如果单元格不可见或 indexPath 超出范围,则返回 nil
  • @KuntalGajjar 我检查了cellForRow 根本没有被调用,我在第一行添加了一个print 消息,但它没有出现。问题在于这一行:self.tview.cellForRow(at: indexPath) as! BigDetailsOnListCell,因为nil 不能转换为BigDetails...。我想那是因为我的手机不见了,但我不确定我在哪一点删除它们
  • 在拉取刷新数据之前,您的刷新控件是否调用 endRefreshing?我的想法是它可能是因为它被称为异步。编辑:当您的表格视图在刷新后向上移动时,滚动视图确实会调用滚动。

标签: ios swift uitableview swift3 tableviewcell


【解决方案1】:

cellForRow(at:) 只会在 tableview 当前具有该行的可见单元格时返回一个单元格。如果没有可见单元格,它将不会调用您的表格视图的数据源方法来获取单元格,它将返回nil

您需要处理cellForRow(at:) 可能返回nil 的事实。不要强行打开它。使用有条件的展开。与indexPathsForVisibleRows 类似;也没有充分的理由强制解开该值。

override func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if (scrollView == self.tview) {
        if let visiblePaths = self.tview.indexPathsForVisibleRows {
            for indexPath in visiblePaths {
                if (indexPath.row < 10) {
                   if let cell = self.tview.cellForRow(at: indexPath as? BigDetailsOnListCell) {
                    self.setCellImageOffset(cell: cell, indexPath: indexPath as NSIndexPath)
                }
            }
        }
    }
}

【讨论】:

  • 对于数组,使用?? [] 更容易。
  • 我的原始代码中确实有这个答案,但我决定更明确。对于刚入门的人来说,nil 合并运算符可能有点“高级”
  • conditional unwrap 在这种情况下等于if(self.tview.cellForRow(at: indexPath) != nil){ 吗?
  • 是的。在 Swift Book 或 Stack overflow 的文档部分阅读有关可选和展开的信息
【解决方案2】:

indexPathsForVisibleRows 中的索引不会向您提供任何关于单元格已显示的保证。注意“可见行”“显示单元格”之间的区别。可见行意味着滚动位置使得该行被显示或显示。它基于可见性计算。另一方面,cellForRow(at:) 基于当前添加为子视图的单元格。

在单元格实际显示之前cellForRow(at:)仍然可以返回nil

这可能在调用reloadTable() 或滚动时立即发生。

【讨论】:

    【解决方案3】:

    在 pullToRefresh 方法中将 yourArray 设为 nil,当你得到响应时它将填充新数据。

    【讨论】:

      【解决方案4】:

      我不知道这是否对任何人都有帮助,但它对我来说很重要。

      override func viewWillDisappear(_ animated: Bool) {
              super.viewWillDisappear(animated)
      
              self.view = nil
          }
      

      这段代码解决了我的问题。我在发送新版本后立即遇到了问题。问题是这个错误,它迫使应用程序在这行代码处崩溃:

      let guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? YourCustomTableViewCell else {...}
      

      我发现当我尝试快速切换视图时总是发生崩溃(我能够切换视图,因为它们位于标签栏控制器中)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多