使用UITableView时如何保留对象的引用?



我面临的问题可能是对可重用单元格的概念缺乏理解。比方说,我要创建 30 行,每行都有一个 UISwitch。

当我切换其中一个开关时,它的行为应该会影响其他 29 个开关。关键是:据我所知,iOS 不会一次创建所有单元格,而是等待在上下滚动 TableView 时重用单元格。

如何保留这些重用对象的副本并告诉 iOS 为开关设置正确的值?

我曾考虑过将单元格附加到 [UISwitch] 中,但我无法将所有 30 个单元格都放在那里,看:

...
var switches = [UISwitch]()
...
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Field10Cell", for: indexPath) as! Field10TableViewCell
    ...
    //cell.value is a UISwitch
    if !switches.contains(cell.value) {
        switches.append(cell.value)
    }
    return cell
}

您可以创建一个集合,用于存储已按下开关的单元格的索引。

var activeSwitches = Set<IndexPath>()

每当用户按下单元格上的开关时,您都会像这样将其存储在集合上:

activeSwitches.insert(indexPath)

如果您需要检查开关是否已激活,只需检查其容器单元的 indexPath 是否位于活动开关中,如下所示:

if activeSwitches.contains(indexPath) {
    // do something
}

为了知道用户何时按下了特定的开关,我建议以下操作:

  1. 在cellForRowAtIndexPath中,将当前indexPath保存到Field10TableViewCell中。
  2. 在 Field10TableViewCell 上创建一个协议并添加一个委托。

    protocol Field10Delegate {
        func didChangeSwitch(value: Bool, indexPath: IndexPath)
    }
    class Field10TableViewCell {
        var delegate: Field10Delegate?
        var indexPath: IndexPath?
        @IBOutlet weak var fieldSwitch: UISwitch! // Can't use 'switch' as a variable name
        @IBAction func switchValueChanged(_ sender: UISwitch) {
            if let indexPath = indexPath {
                delegate?.didChangeSwitch(value: sender.isOn, indexPath: indexPath)
            }
        }
    
  3. 创建单元格时,将视图控制器设置为委托

    let cell = tableView.dequeueReusableCell(withIdentifier: "Field10Cell", for: indexPath) as! Field10TableViewCell
    cell.delegate = self
    cell.indexPath = indexPath
    
  4. 使您的视图控制器符合协议:

    extension ViewController: Field10Delegate {
        /* Whenever a switch is pressed on any cell, this delegate will
           be called. This is a good place also to trigger a update to
           your UI if it has to respond to switch changes.
         */
        func didChangeSwitch(value: Bool, indexPath: IndexPath) {
            if value {
                activeSwitches.insert(indexPath)
            } else {
                activeSwitches.remove(indexPath)
            }
            updateUI()
        }
    }
    

有了上述内容,您可以随时知道哪些交换机处于活动状态或不处于活动状态,并且您可以使用此信息处理已取消排队的单元。

相关内容

最新更新