在本网站的帮助下,我将我的列表(MarketIndex对象数组)作为一个可观察对象:
http://www.drewag.me/posts/swift-kvo-substitute-observable-variables
这是我添加到我的程序中的上述网站的Observable代码:
import Foundation
class Observable: NSObject {
typealias DidChangeHandler = (oldValue: Array<MarketIndex>?, newValue: Array<MarketIndex>) -> ()
dynamic var value : Array<MarketIndex> {
didSet {
for (owner, handlers) in self.observers {
for handler in handlers {
handler(oldValue: oldValue, newValue: value)
}
}
}
}
init(_ value: Array<MarketIndex>) {
self.value = value
super.init()
}
func addObserverForOwner(owner: AnyObject, triggerImmediately: Bool, handler: DidChangeHandler) {
if let index = self.indexOfOwner(owner) {
// since the owner exists, add the handler to the existing array
self.observers[index].handlers.append(handler)
} else {
// since the owner does not already exist, add a new tuple with the
// owner and an array with the handler
self.observers.append(owner: owner, handlers: [handler])
}
if (triggerImmediately) {
// Trigger the handler immediately since it was requested
handler(oldValue: nil, newValue: self.value)
}
}
func removeObserversForOwner(owner: AnyObject) {
if let index = self.indexOfOwner(owner) {
self.observers.removeAtIndex(index)
}
}
// #pragma mark - Private Properties
var observers: [(owner: AnyObject, handlers: [DidChangeHandler])] = []
// #pragma mark - Private Methods
func indexOfOwner(owner: AnyObject) -> Int? {
var index : Int = 0
for (possibleOwner, handlers) in self.observers {
if possibleOwner === owner {
return index
}
index++
}
return nil
}
}
这里是SocketManager的代码,其中包含将成为可观察的MarketIndex对象列表。
import Foundation
class SocketManager: WebSocketDelegate {
class var sharedInstance: SocketManager {
struct Static {
static var onceToken: dispatch_once_t = 0
static var instance: SocketManager? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = SocketManager()
}
return Static.instance!
}
var marketIndexList: Array<MarketIndex> = []
var indexesList: Observable = Observable([])
init() {
}
func getMarketIndexes(inputStream: String) {
// the marketIndexList will be updated from server every time that a value changes in the server
indexesList = Observable(marketIndexList)
println("\(indexesList.value)")
}
println("Market Index List Size: \(indexesList.value.count)")
}
}
现在,我想让我的ViewController成为这个列表的观察者。 我在函数viewDidLoad()中添加了函数addObserverForOwner,但每次列表更改时它都不会更改。 这是我的ViewController的代码:
SocketManager是具有可观察的indicesList的类。此外,SocketManager是Singleton。 notify()函数将更新标签的值并重新加载我的ViewController的tableView。
class IndexViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
SocketManager.sharedInstance.indexesList.addObserverForOwner(self, triggerImmediately: true) { (oldValue, newValue) -> () in
self.marketIndexes = newValue
self.notify()
}
}
func notify() {
updateValues(marketIndexes)
tableView.reloadData()
}
}
我在这里做错了什么?有什么想法吗?
谢谢你们,
答案 0 :(得分:0)
看起来你有一个Observable
对象indexesList
,它有init
方法,如下所示:
init(_ value: Array<MarketIndex>) {
self.value = value
super.init()
}
但请注意Array
是struct
,因此self.value
会获得您传递给它的任何内容的副本。因此,didSet
更新时不会调用marketIndexes
逻辑,而只会更新value
中indexesList
的本地副本(即永远不会)。
此代码示例还有其他问题(我看不到您调用getMarketIndexes
的位置;如果您调用它,它会重新实例化Observable对象,丢弃旧的闭包数组;您想要在关闭时使用[weak self]
或[unowned self]
要小心;等等),但我不确定是否必须担心它们。首先要解决的关键问题是,如果您想要使用其他网站中的此模式,可以退出indexesList
,并将该模式应用于marketIndexes
本身。
在我看来,这严重削弱了Observable
类的价值。这不是可以应用于现有类/属性的通用机制,而是您必须为要添加观察者的每个属性重新实现的模式。你当然可以做到这一点,并且它有效,但感觉有点沉重。
坦率地说,鉴于marketIndexes
是视图控制器的成员本身,我会长时间地思考为什么你不仅仅做更直接的事情:
var marketIndexList: [MarketIndex] = [] {
didSet {
tableView.reloadData()
}
}
如果您正在观察的对象位于不同的类中(即didSet
的类没有办法,那么您可能只会使用“marketIndexList
”模式调用的“闭包数组”模式知道会有多少观察者,特别是观察者想要做什么。而且,即使在那时,我个人也会想到我是否想要自己的观察机制,而不是现有的,完善的模式(通知,KVO / KVN等)。