UITableView的indexPath(用于cell:UITableViewCell) - > IndexPath?为可见细胞返回nil

时间:2017-12-19 11:17:29

标签: ios uitableview

我有点困惑为什么这个方法返回nil: func indexPath(for cell: UITableViewCell) -> IndexPath?

这是一些调试器输出:

(lldb) po expandingCell
<MyApp.BankDetailsTableViewCell: 0x7f9ec307da00; baseClass = UITableViewCell; frame = (0 495.01; 414 258); clipsToBounds = YES; hidden = YES; autoresize = W; layer = <CALayer: 0x60400003ffc0>>

(lldb) po self.tableView.visibleCells
▿ 8 elements
  ▿ 0 : <MyApp.AddressTableViewCell: 0x7f9ec2e49600; baseClass = UITableViewCell; frame = (0 207.01; 414 70); clipsToBounds = YES; autoresize = W; layer = <CALayer: 0x60800022fc40>>
  ▿ 1 : <MyApp.BankDetailsTableViewCell: 0x7f9ec307da00; baseClass = UITableViewCell; frame = (0 277.01; 414 258); clipsToBounds = YES; autoresize = W; layer = <CALayer: 0x60400003ffc0>>
  ▿ 2 : <MyApp.TransactionLinkTableViewCell: 0x7f9ec585d800; baseClass = UITableViewCell; frame = (0 535.01; 414 70); clipsToBounds = YES; autoresize = W; layer = <CALayer: 0x600000025e60>>
  - 3 : <MyApp.SeparatorTableViewCell: 0x7f9ec3003000; baseClass = UITableViewCell; frame = (0 605.01; 414 44); autoresize = W; layer = <CALayer: 0x604000225780>>
  ▿ 4 : <MyApp.GenericFieldTableViewCell: 0x7f9ec3071a00; baseClass = UITableViewCell; frame = (0 649.01; 414 44); autoresize = W; layer = <CALayer: 0x604000226100>>
  ▿ 5 : <MyApp.GenericFieldTableViewCell: 0x7f9ec28eb600; baseClass = UITableViewCell; frame = (0 693.01; 414 44); autoresize = W; layer = <CALayer: 0x6080004337a0>>
  ▿ 6 : <MyApp.GenericFieldTableViewCell: 0x7f9ec590c800; baseClass = UITableViewCell; frame = (0 737.01; 414 44); autoresize = W; layer = <CALayer: 0x600000038b60>>
  ▿ 7 : <MyApp.GenericFieldTableViewCell: 0x7f9ec5849000; baseClass = UITableViewCell; frame = (0 781.01; 414 44); autoresize = W; layer = <CALayer: 0x600000037080>>

(lldb) 

您可以看到展开的单元格位于可见列表中(数组索引1)。那么为什么我的代码为此返回nil?

if let indexPath = self.tableView.indexPath(for: expandingCell) {

   // NEVER REACHES HERE.  Returns nil            

 } else {
    log.warning("This shouldn't happen.  The indexPath should be returned by tableView!")
 }

为了给出一些额外的上下文,我正在响应按下按钮,然后应该在单元格'isExpanded'上设置一个标志,然后我调用self.tableView.beginUpdates()和.endUpdates()(同时为heightForRow(at:...)提供一个新值,以便单元格高度扩大。

2 个答案:

答案 0 :(得分:0)

我并不是真的喜欢使用这种方法,所以我不惜一切代价避免使用它。在您的情况下,如果您真的需要索引路径,我宁愿在数据源请求单元格时分配它。所以在cellForRow中,我将自定义单元格出列并分配其数据对象及其索引路径。

但总的来说这也是一个坏主意(把它放在其他数据源或委托方法中也没什么区别)因为你的数据(例如对象数组)可能会在选择完成时按下(按下按钮)并且你可能会再次遇到麻烦。

所以我发现最好的方法是将对象设置为单元格并将self指定为委托。应该通知单元代表单击某个特定对象的按钮,然后代理可以使用该按钮来扩展单元格...某些代码可能会澄清此过程:

假设您有一个视图控制器,它是表视图的数据源,并且您的表视图显示了MyObject类型的对象,因此您有一些方法可以注入这些对象:

private typealias DataObject = (object: MyObject, extended: Bool) // TODO: use class, not typealias so you can easily change "extended" property for it
private var dataSource: [DataObject] = []
func setDataArray(array: [MyObject]) {
    dataSource = array.map { (object: $0, extended: false) } // TODO: fetch extended from current data source if it exists, else use default
    tableView.reloadData()
}

因此行的单元格看起来像:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell...
        cell.object = dataSource[indexPath.row].object
        cell.delegate = self
        return cell
    }

行的高度:

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        dataSource[indexPath.row].extended ? 100.0 : 44.0
    }

现在是细胞代表:

func myCell(_ sender: MyCell, shouldToggleObjectBeingExtended object: MyObject) {
   if let target = dataSource.first(where: { $0.object === object }) {
       target.extended = !target.extended // To use this you must have a class instead of typealias
       tableView.beginUpdates()
       tableView.endUpdates()
   }
}

我可以想象这可能与你所拥有的有点颠倒,但创建这样一个系统通常会付出很大的代价。在修改源代码时,您完全脱离了表视图,这使事情变得更简单和稳定。我希望它可以帮助你解决问题。

至于根据我的经验,这种方法中的“虫子”总是有点搞笑。通常有一些解决方案,但很少有一个解决方案。

答案 1 :(得分:0)

我只是回答我自己的问题。对我来说,这似乎是UIKit中的一个错误,但无论如何,我刚才补充道 var indexPath: IndexPath? = nil的子类UITableViewCell我将其设置为-tableView:cellForRowAt:并在prepareForReuse

中将其设置为nil

然后我可以直接询问单元格他代表什么indexPath。

看起来不太理想,但它确实有效。