KVO zu verwenden, erklärt das Modellobjekt mit dynamic
Eigenschaften:
class Foo: NSObject {
@objc dynamic var bar: String // in Swift 3, `@objc` is not necessary; in Swift 4 we must make this explicit
init(bar: String) {
self.bar = bar
super.init()
}
}
Dann lassen Sie die Zelle Prozess der KVO. Zuerst würde ich ein Protokoll haben, mit dem die Zelle der Tabellen-Ansicht informieren kann, dass sie neu geladen werden muss:
protocol CustomCellDelegate: class {
func didUpdateObject(for cell: UITableViewCell)
}
Und der Tisch-View-Controller zu diesem CustomCellDelegate
Protokoll anpassen kann und die Zelle neu zu laden, wenn informiert braucht es zu:
func didUpdateObject(for cell: UITableViewCell) {
if let indexPath = tableView.indexPath(for: cell) {
tableView.reloadRows(at: [indexPath], with: .fade)
}
}
So, und dann definieren Zelle zum Einrichten und Umgang mit KVO. In Swift 4 und iOS 11, können Sie die Verschlussbasis observe
Verfahren mit den neuen stark typisierte Tasten verwenden:
class CustomCell: UITableViewCell {
weak var delegate: CustomCellDelegate?
private var token: NSKeyValueObservation?
var object: Foo? {
willSet {
token?.invalidate()
}
didSet {
textLabel?.text = object?.bar
token = object?.observe(\.bar) { [weak self] object, change in
if let cell = self {
cell.delegate?.didUpdateObject(for: cell)
}
}
}
}
}
In Swift 3:
class CustomCell: UITableViewCell {
private var observerContext = 0
weak var delegate: CustomCellDelegate?
var object: Foo? {
willSet {
object?.removeObserver(self, forKeyPath: #keyPath(Foo.bar), context: &observerContext)
}
didSet {
textLabel?.text = object?.bar
object?.addObserver(self, forKeyPath: #keyPath(Foo.bar), context: &observerContext)
}
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard context == &observerContext else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
return
}
delegate?.didUpdateObject(for: self)
}
deinit {
object?.removeObserver(self, forKeyPath: #keyPath(Foo.bar), context: &observerContext)
}
}
Und jetzt kann die cellForRowAtIndexPath
gesetzt nur die delegate
und object
Eigenschaften:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomCell
cell.delegate = self
cell.object = objects![indexPath.row]
return cell
}
meiner Meinung nach ist dies KVO Mechanismus ist besser als der Swift Beobachter-Mechanismus, da t Das Modellobjekt muss nichts über den Beobachter wissen (und sollte es auch nicht). Es muss nur angegeben werden, dass es dynamischen Versand unterstützt, und das ist es.
Für Swift 2 Wiedergabe der oben genannten, siehe previous revision of this answer.
Danke Rob. Ich mochte deine Herangehensweise sehr. – mra214
What's & observerContext in diesem Fall und woher kommt es? – Eden
@Eden - Der 'observeValue (forKeyPath: of: change: context:)' benötigt einen "Kontext", um zu wissen, ob diese Benachrichtigung beobachtet wird oder etwas, das seine 'Super'-Klasse beobachtet. Daher geben wir einen eindeutigen "Kontext" an, der beim Erstellen des Beobachters verwendet und bei der Verarbeitung der Benachrichtigung überprüft wird. Die Standardmethode dafür ist, eine Variable zu definieren, in diesem Fall 'observerContext', und ihre Speicheradresse als diese eindeutige Kennung zu verwenden. Es ist ein übliches Muster, aber ich entschuldige mich, wenn es nicht offensichtlich war. Ich habe es oben hinzugefügt (sowie die einfachere blockbasierte Swift 4, iOS 11 Version). – Rob