gpt4 book ai didi

ios - 如何使用 KVO 根据底层数组元素的变化来更新 tableViewCells?

转载 作者:可可西里 更新时间:2023-11-01 00:56:04 24 4
gpt4 key购买 nike

我有一个表示底层数组的 TableView 。单元格有一个标签和一个 slider , slider 应显示数组的 percentage 属性的值。

我想在百分比属性发生变化时使用键值观察来更新标签。 (我知道 KVO 在这个例子中有点矫枉过正,但最终滑动一个 slider 会影响其他单元格,包括 slider 的位置和底层数组将从应用程序中的多个位置随时设置,所以 KVO 是可行的方法。 )

我得到了很多帮助 from this answer ,但我无法启动它并更新标签。我在这里包括我所有的代码。不知道我哪里错了。

import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, CustomCellDelegate {

@IBOutlet weak var tableView: UITableView!

override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self

for i in 0...4 {
items.append(Items(ID: i, percentage: 50))
}
}

func numberOfSections(in tableView: UITableView) -> Int {
return 1
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

if let cell = tableView.dequeueReusableCell(withIdentifier: myTableViewCell.ID) as? myTableViewCell {
cell.object = items[indexPath.row]
cell.mySlider.tag = indexPath.row

return cell

} else {
return UITableViewCell()
}

}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}


@IBAction func sliderValueChanged(_ sender: UISlider) {
items[sender.tag].percentage = Double(sender.value)
print("percentage at \(items[sender.tag].ID) is \(items[sender.tag].percentage)")
}

func didUpdateObject(for cell: UITableViewCell) {
if let indexPath = tableView.indexPath(for: cell) {
tableView.reloadRows(at: [indexPath], with: .automatic)
print("hello")
}
}
}

class myTableViewCell: UITableViewCell {
static let ID = "myCell"
weak var delegate: CustomCellDelegate?
private var token: NSKeyValueObservation?

var object: Items? {
willSet {
token?.invalidate()
}
didSet {
myLabel.text = "\(object?.percentage ?? 0)"
token = object?.observe(\.percentage) { [weak self] object, change in
if let cell = self {
cell.delegate?.didUpdateObject(for: cell)
}
}
}
}

override func awakeFromNib() {
super.awakeFromNib()
}

@IBOutlet weak var myLabel: UILabel!
@IBOutlet weak var mySlider: UISlider!

}

class Items: NSObject {
let ID: Int
@objc dynamic var percentage: Double

init(ID: Int, percentage: Double){
self.ID = ID
self.percentage = percentage
super.init()
}
}

var items: [Items] = []


protocol CustomCellDelegate: class {
func didUpdateObject(for cell: UITableViewCell)
}

Label not updating

最佳答案

要在 Swift 4 中执行 KVO,您必须将属性声明为 dynamic 并对该对象调用 observe(_:options:changeHandler:),保存生成的 NSKeyValueObservation token 。当该 token 超出范围(或被另一个 token 替换)时,原始观察者将自动删除。

在您的情况下,您让观察者调用委托(delegate),然后委托(delegate)重新加载单元格。但是您似乎从未设置过 delegate 属性,所以我怀疑没有调用该方法。

但这一切似乎都有些脆弱。我倾向于直接在观察者的 changeHandler 中更新标签。我还认为您可以更直接地更新单元格(我将“值已更改”IBAction 放在单元格中,而不是 TableView 中),并消除 tag 的尴尬使用确定模型数组中哪一行的 slider 已更新(如果您插入或删除行,这可能会出现问题)。

所以考虑这个对象:

class CustomObject: NSObject {
let name: String
@objc dynamic var value: Float // this is the property that the custom cell will observe

init(name: String, value: Float) {
self.name = name
self.value = value

super.init()
}
}

然后您可以拥有一个 TableView Controller ,该 Controller 使用此模型类型的实例填充 objects 数组。这里的细节在很大程度上与观察无关(我们将在下面介绍),但我将其包括在内只是为了提供一个完整的示例:

class ViewController: UITableViewController {

var objects: [CustomObject]!

override func viewDidLoad() {
super.viewDidLoad()

// self sizing cells

tableView.estimatedRowHeight = 60
tableView.rowHeight = UITableViewAutomaticDimension

// populate model with random data

let formatter = NumberFormatter()
formatter.numberStyle = .spellOut

objects = (0 ..< 1000).map {
CustomObject(name: formatter.string(for: $0)!, value: 0.5)
}
}
}

// MARK: - UITableViewDataSource

extension ViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects?.count ?? 0
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.object = objects[indexPath.row]
return cell
}
}

完成后,您现在可以让单元格的基类 (a) 如果 slider 发生变化,则更新模型对象; (b) 观察 dynamic 属性的变化,在此示例中,当在模型对象中观察到 value 变化时更新标签:

class CustomCell: UITableViewCell {
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var valueLabel: UILabel!
@IBOutlet weak var valueSlider: UISlider!

static private let formatter: NumberFormatter = {
let _formatter = NumberFormatter()
_formatter.maximumFractionDigits = 2
_formatter.minimumFractionDigits = 2
_formatter.minimumIntegerDigits = 1
return _formatter
}()

private var token: NSKeyValueObservation?

weak var object: CustomObject? {
didSet {
let value = object?.value ?? 0

nameLabel.text = object?.name
valueLabel.text = CustomCell.formatter.string(for: value)
valueSlider.value = value

token = object?.observe(\.value) { [weak self] object, change in
self?.valueLabel.text = CustomCell.formatter.string(for: object.value)
}
}
}

@IBAction func didChangeSlider(_ slider: UISlider) {
object?.value = slider.value
}
}

产生:

enter image description here

有关详细信息,请参阅 Using Swift with Cocoa and Objective-C: Adopting Cocoa Patterns 的“键值观察”部分.

关于ios - 如何使用 KVO 根据底层数组元素的变化来更新 tableViewCells?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48009884/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com