在observeValueForKeyPath中使用switch

时间:2016-01-19 17:33:36

标签: swift switch-statement key-value-observing

我试图通过用一个switch语句替换典型的长嵌套if / else语句来提高我的KVO observeValueForKeyPath实现的可读性。

到目前为止,唯一真正有用的是:

private let application = UIApplication.sharedApplication()

    switch (object!, keyPath!) {

    case let (object, "delegate") where object as? UIApplication === application:
        appDelegate = application.delegate
        break

    ...

    default:
        super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
    }

如果有的话,更难以阅读:

    if object as? UIApplication === application && keyPath! == "delegate" {

    }
    else {

    }

是否有人在observeValueForKeyPath(及类似方法)

中使用开关的良好模型

编辑:与下面的@ critik问题相关,这里有更多的代码来演示使用switch (object as! NSObject, keyPath!) {时出现的问题:

private let application = UIApplication.sharedApplication()
private var appDelegate : UIApplicationDelegate?
private var rootWindow : UIWindow?

public override func observeValueForKeyPath(
    keyPath: String?,
    ofObject object: AnyObject?,
    change: [String : AnyObject]?,
    context: UnsafeMutablePointer<Void>) {

    switch (object as! NSObject, keyPath!) {
    case (application, "delegate"):
        appDelegate = application.delegate
        (appDelegate as? NSObject)?.addObserver(self, forKeyPath: "window", options: [.Initial], context: nil)
        break

    case (appDelegate, "window"):
        rootWindow = appDelegate?.window?.flatMap { $0 }
        break

    case (rootWindow, "rootViewController"):
        rebuildViewControllerList(rootWindow?.rootViewController)
        break

    default:
        super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
    }
}            

2 个答案:

答案 0 :(得分:0)

元组上的switch怎么样:

switch (object as! NSObject, keyPath!) {

case (application, "delegate"):
    appDelegate = application.delegate

...

default:
    super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
}

注意事项1。虽然我再次被迫使用Swift(向下倾斜,解包等),但你可以安全地强制转发NSObject而不会发生崩溃,因为{{{ 3}},KVO仅适用于NSObject子类。

注2。你在Swift中也不需要break,这也会使你的代码缩短至少一行:)

答案 1 :(得分:0)

这并没有真正解决在switch中使用observeValueForKey的问题,但它确实演示了如何简化问题空间以消除冗长的代码。

我创建了一个实用程序类KVOValueWatcher,它允许我在对象的单个属性上添加(和删除)KVO观察:

public class KVOValueWatcher<ObjectType:NSObject, ValueType:NSObject> : NSObject {
    public typealias OnValueChanged = (ValueType?, [String:AnyObject]?) -> ()

    let object : ObjectType
    let keyPath : String
    let options : NSKeyValueObservingOptions
    let onValueChanged : OnValueChanged
    var engaged = false

    public init(object:ObjectType, keyPath:String, options : NSKeyValueObservingOptions = [], onValueChanged: OnValueChanged) {
        self.object = object
        self.keyPath = keyPath
        self.onValueChanged = onValueChanged
        self.options = options

        super.init()

        engage()
    }

    deinit {
        if(engaged) {
            print("KVOValueWatcher deleted without being disengaged")
            print("    object: \(object)")
            print("    keyPath: \(keyPath)")
        }

        disengage()
    }

    public func engage() {
        if !engaged {
            self.object.addObserver(self, forKeyPath: keyPath, options: options, context: nil)
            engaged = true
        }
    }

    public func disengage() {
        if engaged {
            self.object.removeObserver(self, forKeyPath: keyPath)
            engaged = false
        }
    }

    override public func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
        self.onValueChanged(((object as? NSObject)?.valueForKeyPath(keyPath!) as? ValueType), change)
    }
}

我的问题代码变为:

    rootWindowWatcher = KVOValueWatcher(object: applicationDelegate as! NSObject, keyPath: "window", options: [.Initial]) { window, changes in
        self.rootViewWatcher?.disengage()
        self.rootViewWatcher = nil

        if let window = window {
            self.rootViewWatcher = KVOValueWatcher(object: window, keyPath: "rootViewController", options: [.Initial]) {
                [unowned self] rootViewController, changes in
                self.rootViewController = rootViewController
                self.rebuildActiveChildWatchers()
            }
        }
    }

改变的主要原因是因为保持所有不同的观察并正确地添加和删除它们正成为一场噩梦。添加包装类可以消除问题和组观察属性以及属性在同一位置更改时要采取的操作。