if-let语句不解包可选

时间:2015-02-15 20:16:40

标签: ios swift 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语句应该为我打开条件 - 但这不是这里展示的行为。除非我再次打开可选项,否则无法访问window的{​​{1}}属性。 x-code控制台返回以下内容:

subcontrollerView

unwrapped optional和if-let常量相同。为什么呢?

1 个答案:

答案 0 :(得分:6)

您的问题是AnyObject。 (如果有疑问,你的问题总是AnyObject;这是一种应该尽可能避免的邪恶类型。唯一更糟的是AnyObject?。)

问题是tabBarController.viewControllers返回[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的新的if-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;
            } } }