是否可以在 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
我需要在结构类型的变量中跟踪更新。 是否可以在 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