"Who am I" is a big question in both philosophy and programming. In philosophy, it is related to self-consciousness, which in programming, it is introspection.
Introspection is an operation of asking an object to ascertain whether it belongs to a specified type. In Objective-C, id
could point to any object (in fact all pointer in Objective-C could be converted without problem, since they are just used to help the compiler to understand your code). The introspection is used heavily to confirm the type:
[obj1 isKindOfClass:[ClassA class]];
[obj2 isMemberOfClass:[ClassB class]];
-isKindOfClass:
will check obj1
belongs ClassA
or its subclasses; while isMemberOfClass:
checks obj2
exactly belongs ClassB
or not.
These two methods are instance methods of NSObject
, so if we have a subclass of NSObject
in Swift, we can just use them without any modification:
class ClassA: NSObject { }
class ClassB: ClassA { }
let obj1: NSObject = ClassB()
let obj2: NSObject = ClassB()
obj1.isKindOfClass(ClassA.self) // true
obj2.isMemberOfClass(ClassA.self) // false
We have previously discussed about .self
in an earlier tips. If you are not familiar with it, it's a good change to look back.
In the world of Cocoa and Objective-C, almost all types would be subclass of NSObject
. But things changed in Swift. There are a number of Swift types other than classes inherited from NSObject
. For those classes, how can we determine their types?
First thing we should keep in mind is, why should we determine types at runtime? There is generic type in Swift, the types are already known if we follow Swift rules. Most of time, things are set at compile time. If you often need to check and determine the real type of AnyObject
in your code, it might mean some bad smell of it. Although it does not make much sense, we can also check the type of AnyObject
like this:
class ClassA { }
class ClassB: ClassA { }
let obj1: AnyObject = ClassB()
let obj2: AnyObject = ClassB()
obj1.isKindOfClass(ClassA.self) // true
obj2.isMemberOfClass(ClassA.self) // false
The most regular use case of AnyObject
in Swift is in those Cocoa APIs returning id
.
There is a "is" keyword to make things easier in Swift. This keyword is an equivalent with isKindOfClass
, which can be used to check whether an object is an instance of a type or its subtypes. You may notice the words "type" and "subtype", they are not "class" and "subclass". Yes, "is" is more powerful since it can be used on struct
or enum
type as well.
class ClassA { }
class ClassB: ClassA { }
let obj: AnyObject = ClassB()
if (obj is ClassA) {
print("belongs to ClassA")
}
if (obj is ClassB) {
print("belongs to ClassB")
}
P.S. Compiler will consider the necessity of this check: if the compiler could determine the type of object, it will not accept "is
" anymore, but throw an error. This kind of code will not compile:
let string = "String"
if string is String {
// Do something
}
// 'is' test is always true