程序设计和人类哲学锁面临的同一个很重大的课题就是解决“我是谁”
这个问题。在哲学里,这个问题属于自我认知的范畴,而在程序设计中,这个问题涉及自省
(Introspection)。
向一个对象询问它是不是属于某个类。常用的方法有下面两类:
[obj isKindOfClass:[NSObject class]];
[obj isMemberOfClass:[NSObject class]];
- isKindOfClass:
判断obj 是否是NSObject 或者其子类的实例对象- isMemberOfClass:
对obj 做出判断,当且仅当obj 的类型为NSObject 时返回为真。
这两个方法时NSObject 的方法,所以如果在Swift 中写的是NSObject 或其子类的话,直接使用这两个方法时没有任何问题的:
class ClassA: NSObject {}
class ClassB: ClassA {}
let obj1 = ClassB()
let obj2 = ClassB()
obj1.isKind(of: ClassA.self) // true
obj2.isMember(of: ClassA.self) // false
关于.self
的用法,我们在“AnyClass、元类型和.self”中已经有所提及,这里就不再重复了。
在Objective-C
中几乎所有
的类都会是NSObject 的子类
,而在Swift
的世界中,从性能方面考虑,只要有可能,我们应该更倾向于
选择那些非NSObject 子类
的Swift 原生类型。
对于那些不是NSObject 的类,我们应该怎么确定其类型呢?
首先需要明确的一点是,我们为什么要在运行时去确定类型。因为有泛型
支持,Swift 对类型的推断和记录是完备的
。因此在绝大多数情况下,我们使用的Swift 类型
都应该是在编译期间
就确定
的。如果在你写的代码中经常需要检查和确定AnyObject
到底是什么类的话,几乎就意味着你的代码设计
出了问题
(或者你正在写一些充满各种“小技巧”的代码)。虽然没有太多的意义,但是我们还是可以做这件事情:
class ClassA {}
class ClassB: ClassA {}
let obj1: AnyObject = ClassB()
let obj2: AnyObject = ClassB()
obj1.isKind(of: ClassA.self) // true
obj2.isMember(of: ClassA.self) // false
在Swift 中,AnyObject
应用最多的地方应该就是原来那些返回id
的Cocoa API
了。
为了快速确定类型,Swift 提供了一个简洁的写法:对于一个不确定的类型,我们现在可以使用is
来进行判断。is
在功能上相当于原来的isKindOfClass
,可以检查一个对象是否属于某类型或其子类型
。is
和原来的区别
主要在于两点:
- 首先它
不仅
可以用于class 类型
,也可以对Swift 的其他如struct
或enum
等类型进行判断。它在实际使用中是这个样子的:
class ClassA {}
class ClassB: ClassA {}
let obj: AnyObject = ClassB()
if obj is ClassA {
print("属于 ClassA")
}
if obj is ClassB {
print("属于 ClassB")
}
- 另外,编译器将对这种检查进行
必要性判断
:如果编译器能够唯一确定的类型,那么is
的判断就没有必要,编译器将会抛出一个警告
,类似这样的代码:
let string = "String"
if string is String {
// Do something
}
// 'is' test is always true