Ios 点击TableViewCell时未按预期更新UILabel的行数

Ios 点击TableViewCell时未按预期更新UILabel的行数,ios,swift,uikit,tableview,Ios,Swift,Uikit,Tableview,点击自定义UITableViewCell中的标签时,我正在更改标签上的numberOfLines属性。但是,在第二次点击之前,这不会反映在UI中。该单元在表视图中配置为原型单元,最初有2行 有趣的是,当我在我的tapped()函数运行之前和之后打印出numberOfLines值时,值开始不同,然后同步-在第一次点击之后,我看到函数运行之前有2行,然后函数运行之后有0行。但是,在随后的点击之后,我在函数前后看到了相同的值,这使得它看起来好像什么都没做,即使UI确实拉伸和收缩了单元格,并且下次运行d

点击自定义UITableViewCell中的标签时,我正在更改标签上的
numberOfLines
属性。但是,在第二次点击之前,这不会反映在UI中。该单元在表视图中配置为原型单元,最初有2行

有趣的是,当我在我的
tapped()
函数运行之前和之后打印出
numberOfLines
值时,值开始不同,然后同步-在第一次点击之后,我看到函数运行之前有2行,然后函数运行之后有0行。但是,在随后的点击之后,我在函数前后看到了相同的值,这使得它看起来好像什么都没做,即使UI确实拉伸和收缩了单元格,并且下次运行
didselectRowatinedexpath
函数时,
numberOfLines
值会更改

我只在
tableView.reloadRows()
中看到这种行为。如果我使用
tableView.reloadData()
进行完整更新,单元格会在第一次点击时适当地增长和折叠。但是,这感觉有点笨拙,不像
reloadRows()
那样有很好的动画效果

TableView实现

    func tableView(_ tableView: UITableView, 
                       didSelectRowAt indexPath: IndexPath) {
         guard let cell = tableView.cellForRow(at: indexPath) as? ReviewTableViewCell
             else { return }
         let data = tableData[indexPath.row]

         print("old number of lines: \(cell.detailLabel.numberOfLines)")

             //data.isOpen is set to false initially
             cell.tapped(data.isOpen)
         tableData[indexPath.row].isOpen = !data.isOpen
             tableView.reloadRows(at: [indexPath], with: .fade)

             print("old number of lines: \(cell.detailLabel.numberOfLines)")


//      tableView.reloadData()
    }
自定义表视图单元方法

    func tapped(_ isOpen: Bool) {
         if !isOpen {
              detailLabel.numberOfLines = 0     }
         else {
          detailLabel.numberOfLines = 2     }
    }
如果
numberOfLines
设置为0,则在使用
tableView.reloadRows()
重新加载单元格后,我希望此代码会展开单元格,并在设置为2时折叠单元格。这确实有效,但只有在轻敲电池两次以上之后。这也适用于第一次轻触

以下是显示问题的gif链接:


这里有一个与我的应用程序中正在发生的事情类似的示例项目:

只是要清楚,要想让这个技巧发挥作用,
UILabel
通常必须在它的superview的每一面进行约束,这样当它改变它的
intrinsicContentSize
时,它可以推动每一面来容纳文本。
也就是说,试着用这两种方法来包装tapped方法:

tableView.beginUpdates()
if !isOpen {
    detailLabel.numberOfLines = 0     
}
else {
    detailLabel.numberOfLines = 2     
}
tableView.endUpdates()
当然,tableview必须设置为自动大小:

tableView.estimatedRowHeight = <#What you want#>
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight=
tableView.rowHeight=UITableView.automaticDimension

我能够弄清楚发生了什么。问题分为两部分

第一部分是调用
reloadRows()
。此方法是用新单元格替换单元格,而不是更新已存在的单元格。因此,我正在更改隐藏交换单元格上的行数,而不是视图中的单元格。以下内容中提到了此行为:

重新加载行会导致表视图向其数据源请求该行的新单元格。表格在设置旧行的动画时设置新单元格的动画

此外,我使用structs作为数据模型来跟踪单元格的打开状态。在Swift中,结构是写时复制的,这意味着如果在该结构上更改了值,则会创建一个新的结构,而不是更改我指向的该结构的值。这意味着行
tableData[indexath.row].isOpen=!data.isOpen
没有做任何有用的事情-我们在索引路径上查看tableData结构,得到它的
isOpen
值,复制一个新结构并更改该新结构的
isOpen
值,然后抛出它,因为新结构没有分配到任何地方

解决方案是不使用
reloadRows()
方法,而是使用 A) 数据对象的
B) 将indexPath.row处的数据替换为复制的结构

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        guard let cell = tableView.cellForRow(at: indexPath) as? CustomCell else { return }
        var data = tableData[indexPath.row]

        tableView.beginUpdates()
        cell.tapped(isOpen: data.isOpen)
        data.isOpen = !data.isOpen

        tableData[indexPath.row] = data
        tableView.endUpdates()
    }

嘿,谢谢你的回复!我可以确认我已经实现了约束,并且行高度设置为自动。我还尝试了
tableView:didSelectRowAt
中的
beginUpdates()
endUpdates()
方法,但我仍然看到了相同的行为:第一次点击会闪烁单元格并显示更新内容,第二次点击按预期拉伸单元格。你确定没有实现任何“高度”委托方法吗?如果您尝试对其进行注释,请检查我在github上找到的示例代码。我已更新该问题,以在UI中显示该问题的gif,并在我的github上显示一个示例项目,该项目显示了单元格的设置方式以及构建后的行为。