Swift 在observeValueForKeyPath中使用开关

Swift 在observeValueForKeyPath中使用开关,swift,switch-statement,key-value-observing,Swift,Switch Statement,Key Value Observing,我试图通过将嵌套的if/else语句的典型长字符串替换为单个switch语句来提高KVO observeValueForKeyPath实现的易读性 到目前为止,唯一有效的方法是: private let application = UIApplication.sharedApplication() switch (object!, keyPath!) { case let (object, "delegate") where object as? UIApplication

我试图通过将嵌套的if/else语句的典型长字符串替换为单个switch语句来提高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 {

    }
有没有人有一个好的模式来使用switch-in
observeValueForKeyPath
(和类似的方法)

编辑:与下面@critik的问题相关,这里有更多的代码来演示仅使用
开关(对象为!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)
    }
}            
private let application=UIApplication.sharedApplication()
私有var appDelegate:UIApplicationDelegate?
私有var根窗口:UIWindow?
公共覆盖函数observeValueForKeyPath(
键路径:字符串?,
ofObject对象:任何对象?,
更改:[字符串:AnyObject]?,
上下文:unsafemeutablepointer){
开关(对象为!NSObject,keyPath!){
案例(申请,“代表”):
appDelegate=application.delegate
(appDelegate作为?NSObject)?.addObserver(self,forKeyPath:“窗口”,选项:[.Initial],上下文:nil)
打破
案例(appDelegate,“窗口”):
rootWindow=appDelegate?.window?.flatMap{$0}
打破
案例(rootWindow,“rootViewController”):
重建IEWControllerList(rootWindow?.rootViewController)
打破
违约:
super.observeValueForKeyPath(键路径,of对象:object,change:change,context:context)
}
}            

元组上的
开关如何:

switch (object as! NSObject, keyPath!) {

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

...

default:
    super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
}
注1。尽管我在Swift中再次使用强制内容(downcast、unwrapps等),但您可以安全地强制downcast到
NSObject
,而不会发生崩溃,根据,KVO仅适用于
NSObject
子类


注2。在Swift中,您也不需要使用
中断
,这也会将代码至少缩短一行:)

这并不能真正解决在
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)
    }
}

更改的主要原因是,维护所有不同的观察结果并正确添加和删除它们,这将成为一场噩梦。添加包装类可以消除问题,组可以监视属性以及属性在同一位置更改时要采取的操作。

我尝试了一系列强制转换变量iants,但没有尝试NSObject。不幸的是,如果某些目标是可选的,则这似乎不起作用。“UIApplicationLegate类型的表达式模式与NSObject类型的值不匹配”@DavidBerry你能发布失败的代码吗?也许我能找到解决方案:)我想我用足够多的代码更新了它以查看问题。@DavidBerry我用第二个
开关的解决方案更新了我的答案,但这段代码编译了,但它没有做同样的事情。而不是检查
对象==application
,您的代码检查
对象是否为UIApplication
,然后将其分配给名为application的新变量,即,它只执行类型检查。要了解我的意思,请将其更改为
case let(应用程序为UIApplication,“委托”):
看看它是否还能编译。你真正想说的是整个KVO体系结构都很糟糕。这是真的,但这不是什么新鲜事。我们在这条路上走来走去了很多次。有很多明显的解决办法,但最终很难避免一个巨大的瓶颈,所有的东西都通过这一个方法,还有一个巨大的切换“这是处理它的标准方法。@matt现在更让我恼火的是它在iOS上的实现不完全,或者可能使用不完全)。系统对象上有许多属性无法有效地观察,
UIViewController。例如presentedViewController
。谢天谢地。你知道KVO是如何工作的吗?它可以到达r瞄准你的对象并旋转它,用另一个对象替换你的对象!这是魔鬼的工作。事实上,我们有时不得不使用它,这实际上是个问题。是的,我从很早的时候就开始使用KVO。从概念上讲,它是一个非常强大的机制,尤其是在MacOS上,你可以将视图直接绑定到roperty。我经常为在iOS上实现这一点而感到惋惜,因为我已经将解决方案拼凑在一起,至少有几次可以做到这一点:)“你可以将视图直接绑定到属性”当然,我知道。我的应用程序严重依赖于此。但我当然不知道它们是如何工作的
    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()
            }
        }
    }