Reputation: 5397
I am trying to look for instance of specific class in array of different classes (looking for index of specific ViewController in TabBarViewController)
I have a code that checks type using type(of: ) but it doesn't work:
func getTabIndex(_ rootClass: AnyClass) -> Int? {
if let tabVC = UIApplication.shared.delegate?.window?!.rootViewController as? UITabBarController {
for (index, vc) in tabVC.viewControllers!.enumerated() {
if type(of: vc) == rootClass {
return index
}
}
}
return nil
}
if type(of: vc) == rootClass
always returns false.
When I change if type(of: vc) == rootClass
to vc.isMember(of: rootClass)
it works fine.
I assume isMember(of: ) is obj-c method while type(of: ) is pure swift, but I don't see why it would make difference on UIViewController.
Could somebody explain why type(of: ) doesn't work in this case? In both cases, I am comparing exact types, not the subclasses. TabBar has instances of FooViewController and BarViewController. When I call getTabIndex(FooViewController.self)
I get nil when using type(of: ) and 0 when using isMember(of: )
EDIT: I am aware that tpye(of: ) checks for exact type while kind(of: ) checks for subclasses as well, but in my case, I was checking exact type, so type(of: ) should be working fine, hence the confusion.
When I printed result of type(of: ) it was exactly same as when I printed value of rootClass. I know this only means that their textual representation is same and underlying types might be different, but I don't understand why that would be case
EDIT2:
Original question used isKind(of:) method which was misleading, I changed it to isMember(of: ) to reflect more closely source of my confusion, that is why type(of: ) doesn't work when comparing exact types
Upvotes: 0
Views: 597
Reputation: 5397
This issue was cause by Apptimize SDK. They are doing some shady stuff with classes for their UI editor to work. This results in changing type metadata for some classes (views, view controllers) and makes type(of: )
return false even if comparing same types. isMember(of: )
works because it's obj-c method and compares type in different, less rigorous way.
I suspect this can happen with other 3rd party libraries that try to be too clever as well, but in all other cases, type(of: )
should be working without any issues
Upvotes: 0
Reputation: 2794
usage: type(of: instance) == CheckingType.self
return true ONLY when instance
is exactly CheckingType
this method is from stupid Objective-C and required NSObjectProtocol
in swift use instance is CheckingType
usage: instance.isKind(of: CheckingType.self)
return true when instance
is CheckingType
or inherits from CheckingType
Swift version of isKind(of:)
usage: instance is CheckingType
return true when instance
is CheckingType
or inherits from CheckingType
import Foundation
class Animal: NSObject { }
class Cat: Animal { }
Cat() is Cat // true
Cat() is Animal // true
Cat().isKind(of: Animal.self) // true
Cat().isKind(of: Cat.self) // true
type(of: Cat()) == Animal.self // false
type(of: Cat()) == Cat.self // true
Upvotes: 2
Reputation: 54716
Indeed, isKind(of:)
is an Objective-C method that has been around since iOS2, while type(of:)
is indeed a newer Swift method.
Moreover, they are used for different things. Even though in this use case you can achieve the same results using both, they are doing different things. isKind(of:)
only return a bool
indicating whether the receiver is an instance of the class in the parameter value or a class inheriting from that class, while type(of:)
actually returns the dynamic type of the value. Using the latter, you don't have to have any information about the instance, you can still learn its type.
Reference: type(of:), isKind(of:)
Upvotes: 1