首先,我们都知道NSObject是大多数类的根类,但是,这个类的是怎么实现的呢?我们可以去下载开源的Runtime源码,探究下NSObject类的实现。
1. NSObject.h文件
我们可以直接使用Command点NSOject进去看到它的头文件,可以看到,NSObject.h文件中有两块内容:
- NSObject 协议
- NSObject 实现
1.1 NSObject 协议
@protocol NSObject
- (BOOL)isEqual:(id)object;
@property (readonly) NSUInteger hash;
@property (readonly) Class superclass;
- (Class)class OBJC_SWIFT_UNAVAILABLE("use 'type(of: anObject)' instead");
- (instancetype)self;
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
- (BOOL)isKindOfClass:(Class)aClass;
- (BOOL)isMemberOfClass:(Class)aClass;
- (BOOL)conformsToProtocol:(Protocol *)aProtocol;
@end
这里只是粘贴了部分方法,其中也有很多我们熟悉的方法,比如判断代理是否实现某个方法,实现某个协议等等,这个也就解释了,为什么我们自定义的协议也要遵循NSObject的协议,我们可以直接使用NSObject协议中的方法,去判断代理是否实现了,因为协议有Optional这个关键字,协议的方法是可选实现的。
1.2 NSObject的成员变量
我们还是在NSObject.h文件中,可以看到,NSObject只有一个成员变量是Class类型的isa变量:
@interface Object
{
Class isa; /* A pointer to the instance's class structure */
}
那么Class类型是什么类型呢?我们可以大概的猜想一下,可能就是指它所属的类吧。
Now,我们Command继续看这个Class的实现。
1.3 Class是什么玩意?
typedef struct objc_class *Class;
简单明了,Class就是一个指向结构体的指针。关于这一块,不明白结构体指针的,还需要去补充一下这方面的知识。然后,我们继续看 objc_class 这个结构体:
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY; // 还是那个指针
#if !__OBJC2__
Class _Nullable super_class // 父类 OBJC2_UNAVAILABLE;
const char * _Nonnull name // 类名 OBJC2_UNAVAILABLE;
long version // 版本 OBJC2_UNAVAILABLE;
long info // 包含信息 OBJC2_UNAVAILABLE;
long instance_size // 成员变量的size? OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars // 成员变量存储list OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists // 类中的方法 OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache // 类中的方法缓存 OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols // 类中的协议列表 OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
我们这里先看下isa指针:
- isa:在这个结构体中我们看到也有一个isa指针,这个isa指针指向的是meta class,这里补充一下,类其实也是一个对象就是类对象。
搞到这里有点晕了,我们可以看下id类型是个啥类型,可以对比一下。
1.4 id类型
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
我们可以发现,id类型其实也是一个结构体指针啊,这里我们可以看到,objc_object 这个结构体中也有一个 isa变量。So,我们在NSObject,objc_class,objc_object中看到都有一个objc_class *类型,也就是Class类型的变量isa,可见这个isa是多么的重要啊。
我们可以得到大概这样的结论,在objc的runtime中,类是用objc_class结构体表示的,对象是用objc_object结构体表示的,对象的isa用来标示这个对象是哪一个类的实例。我们可以通过几个方法来验证一下。
2. NSObject.m
我们经常使用的判断一个对象是不是某个类或这个类的派生类的实例,那么我们就去看一下这两个方法的实现
- (Class)class {
return object_getClass(self);
}
Class object_getClass(id obj){
if (obj) return obj->getIsa();
else return Nil;
}
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
上面的三个方法简单明了,我们在判断一个对象是否是某个类的实例时,其实就是看这个对象中的isa指针是否指向某个类,当我们调用self class方法时,其实也就是拿到这个实例对象的isa指针,也就是指向结构体objc_class的指针,然后进行判断返回结果。所以,我们可以知道,对于某个普通的对象实例,通过调用[object class]其实返回的就是这个实例的isa变量。
一个类的实例对象的isa指针指向的是这个对象所属的类,这个类描述了一系列它的实例的特点,就像上面的objc_class结构体中的成员变量列表,成员函数的列表等。这个对象能够接受的消息列表也是存储在这个类中。
下面我们也分析一下objc_class,为什么也有一个isa变量呢?
在面向对象的世界中,万物皆对象,所以,类也是一个对象:类对象。它也有一个isa指针,那么它指向谁呢?我们可以看下 +Class方法的实现:
+ (Class)class {
return self;
}
为什么返回的竟然是self呢?我们知道对于某个类的实例来说,self总是指向其自身的,但是这里并没有实例啊,我们是直接调用了这个类的类方法啊,难道类本身也有一个self指针?这个方法的返回值是一个类对象,所以其本质还是一个对象。对于NSObject这样的类来说,它其实也就代表一个类对象,类对象的self指针应该指向的也是这个类对象自身。