I've run across something in my code that seems curious and was wondering if there is a straightforward explanation for this behavior. Given the following statement:
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;
}
}
}
}
Now as far as I know the if-let statement should unwrap the conditional for me--but this is not the behavior exhibited here. I cannot access the window
property of subcontrollerView
unless I unwrap the optional again. The x-code console returns the following:
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>>
The unwrapped optional and the if-let constant are the same. Why?
Your problem is AnyObject
. (When in doubt, your problem is always AnyObject
; it is an evil type that should be avoided as much as possible. The only thing worse is AnyObject?
.)
The trouble is that tabBarController.viewControllers
returns [AnyObject]?
, and optional promotion probably causes things to go sideways. It's likely promoting an AnyObject?
to an AnyObject??
and then getting confused. This is somewhat a compiler bug, but also just the madness that comes with AnyObject
. So the answer is to get rid of it as quickly as you can.
Instead of this:
for subcontroller in tabBarController.viewControllers! {
You want this:
if let viewControllers = tabBarController.viewControllers as? [UIViewController] {
for subcontroller in viewControllers {
So the full code is this:
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;
} } } } }
But we can do better. First, optional chaining is often a better way to manage multiple if-lets, and when it doesn't work well, we can use Swift 1.2's new multi-if-let syntax to get this:
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;
} } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With