是否可以在 Swift 中的结构变量上添加观察者?

Is it possible to add an observer on struct variable in Swift?

我需要在结构类型的变量中跟踪更新。 是否可以在 Swift 中的结构变量上添加观察者?

示例:

struct MyCustomStruct {
    var error:Error?
    var someVar:String?
}

class MyClass{
  var myCustomStruct:MyCustomStruct?
}

我想在 myCustomStruct 变量上添加观察者。

通过变量,您可以使用两个默认观察者

  • 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 Class {
    var myStruct: Struct? {
        didSet {
            ...
        }
    }
}

例如,您也可以在设置变量 post 通知的观察者中使用特定名称

didSet {
    NotificationCenter.default.post(name: Notification.Name("VariableSet"), object: nil)
}

然后您可以添加某些 class 作为观察者以使用此名称

进行通知
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?()
    }
}

}

在你的主要代码中 - main class

var testS = testStruct()
    testS.action = {
        print("Hello")
    }
    testS.variable = "Hi"

当您设置 testS.variabe = "Hi" 时,它将调用 print("Hello")

struct MyCustomStruct {
    var error:Error?
    var someVar:String?
}

class MyClass{
    var myCustomStruct:MyCustomStruct? {
        didSet{
            print("my coustomeSruct changed")
        }
    }
}

let aClass = MyClass()
aClass.myCustomStruct?.someVar = " test"
 //prints:my coustomeSruct changed

标准Swift“property observers” (didSet and willSet) are designed to let a type observe changes to its own properties, but not for letting external objects add their own observers. And KVO, which does support external observers, is only for dynamic and @objc properties NSObject subclasses (as outlined in Using Key-Value Observing in Swift).

所以,如果你想让外部对象观察 struct 内的变化,正如其他人指出的那样,你必须使用 Swift didSet 创建自己的观察者机制之类的。但与其自己实现,属性 by 属性,您可以编写一个泛型类型来为您完成这项工作。例如,

struct Observable<T> {
    typealias Observer = String

    private var handlers: [Observer: (T) -> Void] = [:]

    var value: T {
        didSet {
            handlers.forEach { [=10=].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

值得注意的是,像 Bond or RxSwift 这样的框架提供了这种功能,还有更多。