Ana*_*ore 1 key-value-observing swift
我需要在结构类型的变量中跟踪更新。是否可以在Swift中的struct变量上添加观察者?
例:
struct MyCustomStruct {
var error:Error?
var someVar:String?
}
class MyClass{
var myCustomStruct:MyCustomStruct?
}
Run Code Online (Sandbox Code Playgroud)
我想在myCustomStruct变量上添加一个观察者。
标准的Swift“ 属性观察者 ”(didSet和willSet)旨在让类型观察其自身属性的变化,而不是让外部对象添加自己的观察者。而且,KVO仅支持dynamic和@objc属性NSObject子类(如在Swift中使用键值观察中概述的那样),它确实支持外部观察者。
因此,struct如其他人所指出的那样,如果要让外部对象观察内的变化,则必须使用Swift didSet等创建自己的观察器机制。但是,您可以编写一个泛型类型来代替您自己逐个属性地实现该目的。例如,
struct Observable<T> {
typealias Observer = String
private var handlers: [Observer: (T) -> Void] = [:]
var value: T {
didSet {
handlers.forEach { $0.value(value) }
}
}
init(_ value: T) {
self.value = value
}
@discardableResult
mutating func observeNext(_ handler: @escaping (T) -> Void) -> Observer {
let key = UUID().uuidString as Observer
handlers[key] = handler
return key
}
mutating func remove(_ key: Observer) {
handlers.removeValue(forKey: key)
}
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以执行以下操作:
struct Foo {
var i: Observable<Int>
var text: Observable<String>
init(i: Int, text: String) {
self.i = Observable(i)
self.text = Observable(text)
}
}
class MyClass {
var foo: Foo
init() {
foo = Foo(i: 0, text: "foo")
}
}
let object = MyClass()
object.foo.i.observeNext { [weak self] value in // the weak reference is really only needed if you reference self, but if you do, make sure to make it weak to avoid strong reference cycle
print("new value", value)
}
Run Code Online (Sandbox Code Playgroud)
然后,当您更新属性时(例如,如下所示),将调用观察者处理程序闭包:
object.foo.i.value = 42
Run Code Online (Sandbox Code Playgroud)
值得注意的是,诸如Bond或RxSwift之类的框架提供了这种功能,还有更多功能。
对于变量,您可以使用两个默认观察者
willSet - 表示变量将被设置为新值之前的时刻
didSet - 表示设置变量的时刻
同样在观察者中,您可以使用两个值。当前状态下的当前变量,以及取决于观察者的常数
struct Struct {
var variable: String {
willSet {
variable // before set
newValue // after set, immutable
}
didSet {
oldValue // before set, immutable
variable // after set
}
}
}
Run Code Online (Sandbox Code Playgroud)
您可以对任何其他存储属性执行相同的操作,因此您也可以将其用于类中的 struct 变量
class Class {
var myStruct: Struct? {
didSet {
...
}
}
}
Run Code Online (Sandbox Code Playgroud)
例如,您还可以在 do set Observer of variable post notice 中使用特定名称
didSet {
NotificationCenter.default.post(name: Notification.Name("VariableSet"), object: nil)
}
Run Code Online (Sandbox Code Playgroud)
然后您可以添加某个类作为观察者以使用此名称进行通知
class Class {
init() {
NotificationCenter.default.addObserver(self, selector: #selector(variableSet), name: Notification.Name("VariableSet"), object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self, name: Notification.Name("VariableSet"), object: nil)
}
@objc func variableSet() {
...
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1367 次 |
| 最近记录: |