如何在swift中创建一个视图控制器观察者?

时间:2015-03-08 13:38:00

标签: ios swift observers

在本网站的帮助下,我将我的列表(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()
    }
    }

我在这里做错了什么?有什么想法吗?

谢谢你们,

1 个答案:

答案 0 :(得分:0)

看起来你有一个Observable对象indexesList,它有init方法,如下所示:

init(_ value: Array<MarketIndex>) {
    self.value = value
    super.init()
}

但请注意Arraystruct,因此self.value会获得您传递给它的任何内容的副本。因此,didSet更新时不会调用marketIndexes逻辑,而只会更新valueindexesList的本地副本(即永远不会)。

此代码示例还有其他问题(我看不到您调用getMarketIndexes的位置;如果您调用它,它会重新实例化Observable对象,丢弃旧的闭包数组;您想要在关闭时使用[weak self][unowned self]要小心;等等),但我不确定是否必须担心它们。首先要解决的关键问题是,如果您想要使用其他网站中的此模式,可以退出indexesList,并将该模式​​应用于marketIndexes本身。

在我看来,这严重削弱了Observable类的价值。这不是可以应用于现有类/属性的通用机制,而是您必须为要添加观察者的每个属性重新实现的模式。你当然可以做到这一点,并且它有效,但感觉有点沉重。

坦率地说,鉴于marketIndexes是视图控制器的成员本身,我会长时间地思考为什么你不仅仅做更直接的事情:

var marketIndexList: [MarketIndex] = [] {
    didSet {
        tableView.reloadData()
    }
}

如果您正在观察的对象位于不同的类中(即didSet的类没有办法,那么您可能只会使用“marketIndexList”模式调用的“闭包数组”模式知道会有多少观察者,特别是观察者想要做什么。而且,即使在那时,我个人也会想到我是否想要自己的观察机制,而不是现有的,完善的模式(通知,KVO / KVN等)。