Sea*_*ean 3 key-value-observing ios swift
我有一个代表底层数组的表视图。percentage这些单元格有一个标签和一个滑块,应显示数组属性的值。
我想在百分比属性发生变化时使用键值观察来更新标签。(我知道 KVO 在这个例子中有点矫枉过正,但最终滑动一个滑块会影响其他单元格,包括滑块的位置,并且底层数组将从应用程序中的多个位置随时设置,因此 KVO 是可行的方法。 )
我从这个答案中得到了很多帮助,但我无法让它启动并更新标签。我在这里包含了我的所有代码。不知道我哪里错了。
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)
}
Run Code Online (Sandbox Code Playgroud)
要在 Swift 4 中执行 KVO,您必须将属性声明为dynamic并调用observe(_:options:changeHandler:)该对象,保存生成的NSKeyValueObservation令牌。当该令牌超出范围(或被另一个令牌替换)时,原始观察者将自动被删除。
在您的情况下,您的观察者调用委托,然后委托重新加载单元格。但您似乎从未设置过该delegate属性,因此我怀疑该方法没有被调用。
但这一切似乎都有点脆弱。我倾向于直接在观察者的changeHandler. 我还认为您可以对单元格进行更直接的更新(我将“值已更改”IBAction 放入单元格中,而不是表视图中),并消除对tag识别模型数组中的哪一行的相当尴尬的情况更新了其滑块(如果插入或删除行,这可能会出现问题)。
所以考虑这个对象:
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()
}
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以有一个表视图控制器来填充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
}
}
Run Code Online (Sandbox Code Playgroud)
完成此操作后,您现在可以让单元格的基类 (a) 在滑块发生变化时更新模型对象;(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
}
}
Run Code Online (Sandbox Code Playgroud)
得出:
有关更多信息,请参阅《使用 Swift 与 Cocoa 和 Objective-C:采用 Cocoa 模式》的“键值观察”部分。
| 归档时间: |
|
| 查看次数: |
1707 次 |
| 最近记录: |