UICollectionView状态恢复:恢复所有的UICollectionViewCells

UICollectionView state restoration: restore all UICollectionViewCells

我通过Google和SO搜索了很多,所以如果这个问题已经得到回答,请原谅我!

问题: 我有一个 UICollectionView 和 n UICollectionViewCells。每个单元格都包含来自 XIB 文件的 UIView。视图用于数据输入,因此所有单元格都有唯一的 reuseIdentifier。每个视图也有一个唯一的 restorationIdentifier。正常使用一切正常,但在状态恢复时却不行:

前 3 或 4 个单元格正在正确恢复,因为它们在启动时在屏幕上可见,但其余不可见的单元格未恢复。

当前解法: 所以到目前为止我发现只有在启动时将视图添加到用户界面时才会恢复视图。 我目前的工作解决方案是在恢复过程中将所有单元格的高度设置为1。现在每个单元格都已加载并且所有视图都已恢复。 调用 applicationFinishedRestoringState() 时,我重新加载具有正确高度的 CollectionView。

现在我的问题是:我对这个解决方案不满意,是否有更干净的方法来实现所有 UIView 的恢复?

我认为您有点混淆了数据模型和视图。首次初始化时,您的 table 视图是根据数据模型构建的,提取存储的值以填充每个单元格中的任何内容。但是,您的用户并不直接与数据模型交互,而是与屏幕上的视图交互。如果用户在 table 视图中更改了某些内容,您需要将该更改发回给视图控制器,以便它可以将更改记录到数据模型中。这反过来意味着,如果需要重新创建视图,则视图控制器具有重建应用程序进入后台时 table 中的任何内容所需的信息。

我在这里整理了一个简单的 gitHub 存储库:https://github.com/mpj-chandler/StateManagementDemo

这包括一个 CustomTableViewController class,它管理一个填充有 CustomTableViewCells 的标准 UITableView。自定义单元格包含三个开关按钮,允许每个单元格的状态由布尔值数组表示。

我为单元格创建了一个委托协议,这样如果任何开关被触发,信号就会发送回视图控制器:

protocol CustomTableViewCellDelegate {
    func stateDidChange(sender: CustomTableViewCell) -> Void
}

// Code in CustomTableViewCell.swift:

@objc fileprivate func switched(sender: UISwitch) -> Void {

    guard let index : Int = switches.index(of: sender) else { return }

    state[index] = sender.isOn   
}

// The cell's state is an observed parameter with the following didSet method:

fileprivate var state : [Bool] = Array(repeating: false, count: 3) {
    didSet {
        if state != oldValue, let _ = delegate {
            delegate!.stateDidChange(sender: self)
        }
    }
}

CustomTableViewController注册到CustomTableViewCellDelegate协议,这样它就可以记录模型中的变化,如下:

// Code in CustomTableViewController.swift

//# MARK:- CustomTableViewCellDelegate methods

internal func stateDidChange(sender: CustomTableViewCell) -> Void {
    guard let indexPath : IndexPath = tableView.indexPath(for: sender) else { return }
    guard indexPath.row < model.count else { print("Error in \(#function) - cell index larger than model size!") ; return }

    print("CHANGING MODEL ROW [\(indexPath.row)] TO: \(sender.getState())")
    model[indexPath.row] = sender.getState()

}

你可以看到这里设置了将模型更改输出到控制台的功能。

如果您 运行 模拟器中的项目并退出到主屏幕并再次返回,您将看到 tableView 单元格的状态被保留,因为模型反映了是在应用进入后台之前制作的。

希望对您有所帮助。