1

I'm trying to understand where this code went wrong given the code below. In the code below, I'm trying to locate a UIViewController of a specific class in the UITabBarController's viewControllers property which is declared as:

var viewControllers: [AnyObject]?

So I'm defining two UIViewController subclasses and stuffing them to the viewControllers array and running two different methods to extract them "viewControllerInfo:" ""viewControllerInfo2". Which both yield the same result.

My understanding is the: if let x as? T will evaluate true and assign x as a "T" type if it is the same class. Just as if x is T would.

Any idea why evaluation is behaving like this ?

class VC1: UIViewController {}

class VC2: UIViewController {}

let tabBar = UITabBarController()
tabBar.viewControllers = [VC1(), VC2()]

extension UITabBarController {

    public func viewControllerInfo<T: UIViewController>(ofType: T.Type) -> (viewController: T,index: Int)? {
        if let tabViewControllers = self.viewControllers{
            for  (idx, maybeVCTypeT) in enumerate(tabViewControllers) {
                if let viewController = maybeVCTypeT as? T {
                    return (viewController, idx)
                }
            }

        }
        return nil
    }

    public func viewControllerInfo2<T: UIViewController>(ofType: T.Type) -> (viewController: T,index: Int)? {
        if let tabViewControllers = self.viewControllers{
            for  (idx, maybeVCTypeT) in enumerate(tabViewControllers) {
                if maybeVCTypeT is T {
                    return (maybeVCTypeT as! T, idx)
                }
            }

        }
        return nil
    }


}

All the tests below will end up giving exactly the same result: "<__lldb_expr_89.VC1: 0x7f85016079f0>"

if let (vc, idx) = tabBar.viewControllerInfo(VC1.self) {
    println(vc)
}

if let (vc, idx) = tabBar.viewControllerInfo(VC2.self) {
    println(vc)
}

if let (vc, idx) = tabBar.viewControllerInfo2(VC1.self) {
    println(vc)
}

if let (vc, idx) = tabBar.viewControllerInfo2(VC2.self) {
    println(vc)
}

I'm suspicious of the enumerate(x) since without it I'm getting expected results:

if testVC1 is VC2 {
    println("\(testVC1) is \(VC2.self)")
}

the above code yields a warning:

Cast from 'VC1' to unrelated type 'VC2' always fails Which is what i'm trying to achieve with enumerate...

enter image description here

***************** EDIT *****************

Actually my suspicion of enumerate is dissolved after running the following code which ran perfectly.

let myArray: [AnyObject] = [VC2(), VC1()]
for (idx, x) in enumerate(myArray) {
    println(x)
    if let xAsVC1 = x as? VC1 {
        println("\(x) is supposed to be \(VC1.self)")
//"<__lldb_expr_155.VC1: 0x7fc12a9012f0> is supposed to be __lldb_expr_155.VC1"

    }

    if x is VC2 {
        println("\(x) is supposed to be \(VC2.self)")
//"<__lldb_expr_155.VC2: 0x7fc12a900fd0> is supposed to be __lldb_expr_155.VC2"

    }
}
Edward Ashak
  • 2,411
  • 2
  • 23
  • 38

1 Answers1

0

This seems to be caused by the generic constraint, and I believe is a bug (http://www.openradar.me/22218124). Removing the generic constraint, or making it a non-ObjC class (such as AnyObject) seems to fix it:

public func viewControllerInfo<T>(ofType: T.Type) -> (viewController: T,index: Int)? {

You can also replace:

            if maybeVCTypeT is T {

with:

            if maybeVCTypeT.isKindOfClass(T) {

And that seems to work.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • I just tried the same but with isKindOfClass check and I got the same VC1 class object against testing with VC1 and VC2 ... The interesting thing is that this exact code works find outside of the extension. not sure why yet – Edward Ashak Aug 10 '15 at 20:42
  • That's strange; I'm seeing it working as you'd expect w/ isKindOfClass. I get VC1 and VC2. Here's my playground. I get VC1, VC2, VC1, VC2. Testing w/ 6.4 – Rob Napier Aug 10 '15 at 20:46
  • Could this be the same problem http://stackoverflow.com/questions/25838032/optional-binding-succeeds-if-it-shouldnt ? – Martin R Aug 10 '15 at 21:01
  • You're totally right, having the UIViewController constraint on the signature is whats messing it up :) Thanks @Rob – Edward Ashak Aug 10 '15 at 21:03
  • I think it is essentially the same issue, I never knew about this behavior. Seems like an Apple bug to me, no ? – Edward Ashak Aug 10 '15 at 21:06