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

问题描述 投票:0回答:5

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

示例:

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

class MyClass{
  var myCustomStruct:MyCustomStruct?
}

我想在

myCustomStruct
变量上添加一个观察者。

swift key-value-observing
5个回答
12
投票

标准 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


值得注意的是,像
Bond

RxSwift 这样的框架提供了此类功能,以及更多功能。


6
投票

  • 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() { ... } }



0
投票

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")


0
投票

但是你可以做类似的事情

final public class WrapperStruct<T>: ObservableObject { @Published public var value: T public init(_ value: T) { self.value = value } }

然后调用创建结构,如下所示:

@ObservedObject private var myStruct: WrapperStruct<MyStruct>

https://www.swiftjectivec.com/observing-structs-swiftui/

我怀疑这是否是一个好方法,但似乎有效。


-3
投票
© www.soinside.com 2019 - 2024. All rights reserved.