问题
以下代码输出结果是什么?
BOOL res1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
BOOL res2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
BOOL res3 = [(id)[Sark class] isKindOfClass:[Sark class]];
BOOL res4 = [(id)[Sark class] isMemberOfClass:[Sark class]];
BOOL res5 = [(id)[[NSObject alloc] init] isKindOfClass:[NSObject class]];
BOOL res6 = [(id)[[NSObject alloc] init] isMemberOfClass:[NSObject class]];
BOOL res7 = [(id)[[Sark alloc] init] isKindOfClass:[Sark class]];
BOOL res8 = [(id)[[Sark alloc] init] isMemberOfClass:[Sark class]];
NSLog(@"%d %d %d %d %d %d %d %d", res1, res2, res3, res4,res5,res6,res7,res8);
//Sark继承于NSObject
现在我们来一步一步解析上述代码:
isKindOfClass & isMemberOfClass
苹果官方文档对isKindOfClass的解释是:
Returns a Boolean value that indicates whether the receiver is an instance of given class or an instance of any class that inherits from that class.
gnustep中给出的实现代码为:
/**
* Returns YES if aClass is the NSObject class
*/
+ (BOOL) isKindOfClass: (Class)aClass
{
if (aClass == [NSObject class])
return YES;
return NO;
}
/**
* Returns YES if the class of the receiver is either the same as aClass
* or is derived from (a subclass of) aClass.
*/
- (BOOL) isKindOfClass: (Class)aClass
{
Class class = object_getClass(self);
return GSObjCIsKindOf(class, aClass);
}
对isMemberOfClass的解释是:
Returns a Boolean value that indicates whether the receiver is an instance of a given class.
gnustep中给出的实现代码为:
/**
* Returns YES if aClass is the same as the receiving class.
*/
+ (BOOL) isMemberOfClass: (Class)aClass
{
return (self == aClass) ? YES : NO;
}
/**
* Returns YES if the class of the receiver is aClass
*/
- (BOOL) isMemberOfClass: (Class)aClass
{
return ([self class] == aClass) ? YES : NO;
}
其中class方法的实现为
/**
* Returns the receiver.
*/
+ (Class) class
{
return self;
}
/**
* Returns the class of which the receiver is an instance.<br />
* The default implementation returns the actual class that the
* receiver is an instance of.<br />
* NB. When NSZombie is enabled (see NSDebug.h) this is changed
* to be the NSZombie class upon object deallocation.
*/
- (Class) class
{
return object_getClass(self);
}
看到这里我们应该对这两个函数的意思很明白了。
isKindOfClass 判断的是该对象是否是该类以及该类子类的实例。
isMemberOfClass 判断的是该对象是否是该类的实例。
现在我们来看看object和class的内部结构(有删减):
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
/// Represents an instance of a class.
struct objc_object {
Class isa;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
struct objc_class {
Class isa; // 指向metaclass
Class super_class ; // 指向其父类
const char *name ; // 类名
long version ; // 类的版本信息,初始化默认为0,可以通过runtime函数class_setVersion和class_getVersion进行修改、读取
long info; // 一些标识信息,如CLS_CLASS (0x1L) 表示该类为普通 class ,其中包含对象方法和成员变量;CLS_META (0x2L) 表示该类为 metaclass,其中包含类方法;
long instance_size ; // 该类的实例变量大小(包括从父类继承下来的实例变量);
struct objc_ivar_list *ivars; // 用于存储每个成员变量的地址
struct objc_method_list **methodLists ; // 与 info 的一些标志位有关,如CLS_CLASS (0x1L),则存储对象方法,如CLS_META (0x2L),则存储类方法;
struct objc_cache *cache; // 指向最近使用的方法的指针,用于提升效率;
struct objc_protocol_list *protocols; // 存储该类遵守的协议
}
由此可知,在OC中,类也是一个对象都是一个含有isa指针的结构体。
其中isa指向所属Class, super_class指向父类别。
isa指针
根据上面的gnustep源码,我们知道:
isKindOfClass的实现是通过比较isa指针是否指向同一个类(元类),如果不是就比较父类的isa指针,直到isa指向了NSObject的isa,如果还未相等就返回NO。
isMemberOfClass的实现是通过比较isa指针是否指向同一个类(元类),如果相同就返回YES。
那么此时答案就很显然了:1 0 0 0 1 1 1 1
参考资料:
gnustep源码、 深入理解Class