if-let 语句不解包可选

if-let statement doesn't unwrap optional

我 运行 在我的代码中发现了一些看起来很奇怪的东西,想知道是否有针对此行为的直接解释。给定以下语句:

    if let tabBarController = topViewController as? UITabBarController {
        for subcontroller in tabBarController.viewControllers! {
            println(subcontroller.view)
            if let subcontrollerView = subcontroller.view {
                println(subcontrollerView)
                println(subcontrollerView!)
                if subcontrollerView!.window != nil && subcontroller.isViewLoaded() {
                    topViewController = subcontroller as? UIViewController
                    break;
                }
            }
        }
    }

据我所知,if-let 语句应该为我解开条件语句——但这不是这里展示的行为。我无法访问 subcontrollerViewwindow 属性 除非我再次打开可选的。 x-code控制台returns如下:

Optional(<UILayoutContainerView: 0x7fbccd44e7f0; frame = (0 0; 320 568); autoresize = W+H; gestureRecognizers = <NSArray: 0x7fbccacdde90>; layer = <CALayer: 0x7fbccd440e30>>)
Optional(<UILayoutContainerView: 0x7fbccd44e7f0; frame = (0 0; 320 568); autoresize = W+H; gestureRecognizers = <NSArray: 0x7fbccacdde90>; layer = <CALayer: 0x7fbccd440e30>>)
<UILayoutContainerView: 0x7fbccd44e7f0; frame = (0 0; 320 568); autoresize = W+H; gestureRecognizers = <NSArray: 0x7fbccacdde90>; layer = <CALayer: 0x7fbccd440e30>>  

解包的可选和 if-let 常量是一样的。为什么?

您的问题是AnyObject。 (有疑问的时候,你的问题总是AnyObject;是邪恶的类型,应该尽量避免。唯一更糟糕的是AnyObject?。)

麻烦的是tabBarController.viewControllers returns [AnyObject]?,可选的晋升可能会导致事情走向一边。它可能会将 AnyObject? 提升为 AnyObject?? 然后变得困惑。这在某种程度上是一个编译器错误,但也只是 AnyObject 带来的疯狂。所以答案是尽快摆脱它。

而不是这个:

for subcontroller in tabBarController.viewControllers! {

你想要这个:

if let viewControllers = tabBarController.viewControllers as? [UIViewController] {
   for subcontroller in viewControllers {

所以完整的代码是这样的:

if let tabBarController = topViewController as? UITabBarController {
    if let viewControllers = tabBarController.viewControllers as? [UIViewController] {
        for subcontroller in viewControllers {
            if let subcontrollerView = subcontroller.view {
                if subcontrollerView.window != nil && subcontroller.isViewLoaded() {
                    topViewController = subcontroller
                    break;
                } } } } }

但我们可以做得更好。首先,可选链接通常是管理多个 if-let 的更好方法,当它效果不佳时,我们可以使用 Swift 1.2 的新 multi-if-let 语法来实现:

if let tabBarController = topViewController as? UITabBarController,
    viewControllers = tabBarController.viewControllers as? [UIViewController] {
        for subcontroller in viewControllers {
            if subcontroller.view?.window != nil && subcontroller.isViewLoaded() {
                topViewController = subcontroller
                break;
            } } }