我需要在结构类型的变量中跟踪更新。 可以在Swift中的struct变量上添加观察者吗?
示例:
struct MyCustomStruct {
var error:Error?
var someVar:String?
}
class MyClass{
var myCustomStruct:MyCustomStruct?
}
我想在myCustomStruct
变量上添加观察者。
答案 0 :(得分:4)
标准的Swift“ property observers”(didSet
和willSet
)旨在让类型观察其自身属性的变化,而不是让外部对象添加自己的观察者。而且确实支持外部观察者的KVO仅适用于dynamic
和@objc
属性NSObject
子类(如Using Key-Value Observing in 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
答案 1 :(得分:3)
使用变量,您可以使用两个默认观察者
willSet
-表示将变量设置为新值之前的时刻
didSet
-表示设置变量的时刻
还可以在观察者中使用两个值。当前状态下的电流变量为常数,视观察者而定
struct Struct {
var variable: String {
willSet {
variable // before set
newValue // after set, immutable
}
didSet {
oldValue // before set, immutable
variable // after set
}
}
}
您可以对任何其他存储属性执行相同操作,因此也可以将其用于类中的struct变量
class Class {
var myStruct: Struct? {
didSet {
...
}
}
}
例如,您还可以在具有特定名称的变量后通知的set set观察器中
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() {
...
}
}
答案 2 :(得分: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”)
答案 3 :(得分:-1)
当然,您可以使用didSet,willSet或set。这是一个示例:
class MyClass {
var someStruct: SomeStruct {
didSet {
print("structure variable was changed")
}
}
}
如果要通知另一个对象有关更改的信息,则可以添加回调。
答案 4 :(得分:-2)
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