我正在Struct
模型对象上实现观察者设计模式。我的想法是,我将沿着一个UIViewController
链传递我的模型,并且随着每个控制器的修改,以前的控制器也将随着对象的更改而更新。
我知道可以通过使用class
而不是struct
并通过引用直接修改对象来解决此问题,但是我试图学习有关使用structs
的更多信息
struct ModelObject {
var data: Int = 0 {
didSet {
self.notify()
}
}
private var observers = [ModelObserver]()
mutating func attachObserver(_ observer: ModelObserver){
self.observers.append(observer)
}
private func notify(){
for observer in observers {
observer.modelUpdated(self)
}
}
}
protocol ModelObserver {
var observerID: Int { get }
func modelUpdated(_ model: ModelObject)
}
class MyViewController : UIViewController, ModelObserver {
var observerID: Int = 1
var model = ModelObject()
override func viewDidLoad() {
self.model.attachObserver(self)
self.model.data = 777
}
func modelUpdated(_ model: ModelObject) {
print("received updated model")
self.model = model //<-- problem code
}
}
简而言之,当data
发生变化时,我的模型对象通过调用notify()
通知任何观察者。
我现在的问题是内存访问:data
设置为777
时,self.model
被独占访问,并且当它调用notify
时又调用{{1} },最后modelUpdated
,我们得到一个错误:
self.model = model
如何解决此内存访问问题?
答案 0 :(得分:1)
如果您正在观察“事物”,则该“事物”具有身份。您正在观察这件事。您无法观察到数字4。它没有身份。每4个与其他4个相同。结构是值。他们没有身份。您不应像观察Int那样尝试观察它们(Int实际上是Swift中的结构)。
每次将结构传递给函数时,都会复制该结构。因此,当您说self.model = model
时,是在说“制作模型的副本并将其分配给此属性”。但是您仍然处于排他性访问块中,因为每次修改结构时,该结构也会产生一个副本。
如果您打算观察ModelObject,则ModelObject应该是引用类型,类。然后,您可以谈论“此特定ModelObject”,而不是“包含这些值的ModelObject,并且与包含相同值的任何其他ModelObject都没有区别。”