我需要跟踪结构类型变量的更新。 是否可以在 Swift 中的结构变量上添加观察者?
示例:
struct MyCustomStruct {
var error:Error?
var someVar:String?
}
class MyClass{
var myCustomStruct:MyCustomStruct?
}
我想在
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)
}
}
然后你可以做这样的事情:
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)
}
然后,当您更新属性时,例如如下所示,您的观察者处理程序闭包将被调用:
object.foo.i.value = 42
值得注意的是,像
或 RxSwift 这样的框架提供了此类功能,以及更多功能。
willSet
- 表示变量将被设置新值之前的时刻
didSet
- 表示设置变量的时刻
struct Struct {
var variable: String {
willSet {
variable // before set
newValue // after set, immutable
}
didSet {
oldValue // before set, immutable
variable // after set
}
}
}
您可以对任何其他存储属性执行相同的操作,因此您也可以将其用于类中的结构变量
class Class {
var myStruct: Struct? {
didSet {
...
}
}
}
您还可以例如在确实设置具有特定名称的变量发布通知的观察者
didSet {
NotificationCenter.default.post(name: Notification.Name("VariableSet"), object: nil)
}
然后您可以添加某个类作为观察者以使用此名称进行通知
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() {
...
}
}
struct testStruct {
var action: (()->())?
var variable: String? {
didSet {
self.action?()
}
}
}
在你的主代码中 - 主类
var testS = testStruct()
testS.action = {
print("Hello")
}
testS.variable = "Hi"
当你设置 testS.variabe = "Hi" 时,它会调用 print("Hello")
但是你可以做类似的事情
final public class WrapperStruct<T>: ObservableObject {
@Published public var value: T
public init(_ value: T) {
self.value = value
}
}
然后调用创建结构,如下所示:
@ObservedObject private var myStruct: WrapperStruct<MyStruct>