+-
【iOS笔记 #10】isKindOfClass与isMemberOfClass

iOS笔记系列目录

一 Code


- (void)testClassISA {

id b1 = [NSObject class];

id b2 = [NSObject class];

id b3 = [[NSObject new] class];

NSLog(@"[NSObject class] = %@ , %@, %@", b1,b2,b3);

// true
BOOL res1 = [(id)[NSObject class] isKindOfClass:(id)[NSObject class]];

// false
BOOL res2 = [(id)[NSObject class] isMemberOfClass:(id)[NSObject class]];

// true
BOOL res3 = [(id)[[NSObject new] class] isKindOfClass:(id)[NSObject class]];

// false
BOOL res4 = [(id)[[NSObject new] class] isMemberOfClass:(id)[NSObject class]];

// true
BOOL res5 = [(id)[[NSObject new] class] isKindOfClass:(id)[NSObject class]];

// true
BOOL res6 = [(id)[[NSObject new] class] isMemberOfClass:(id)[NSObject class]];

// false
BOOL res7 = [(id)[Test class] isKindOfClass:(id)[Test class]];

// false
BOOL res8 = [(id)[Test class] isKindOfClass:(id)[Test class]];

// false
BOOL res9 = [(id)[[Test new] class] isKindOfClass:(id)[Test class]];

// false
BOOL res10 = [(id)[[Test new] class] isMemberOfClass:(id)[Test class]];

// true
BOOL res11 = [(id)[Test new] isKindOfClass:(id)[Test class]];

// true
BOOL res12 = [(id)[Test new] isMemberOfClass:(id)[Test class]];

// 1, 0, 1, 0, 1, 1
NSLog(@"%d, %d, %d, %d, %d, %d",res1, res2, res3,res4,res5, res6);

// 0, 0, 0, 0, 1, 1
NSLog(@"%d, %d, %d, %d, %d, %d",res7, res8, res9,res10,res11, res12);

}

二 源码

0.源码解析


/// 类方法,返回自身

+ (Class)class {

return self;

}

/// 实例方法,查找isa(类)

- (Class)class {

return object_getClass(self);

}

Class object_getClass(id obj)

{

if (obj) return obj->getIsa();

else return Nil;

}

inline Class

objc_object::getIsa()

{

if (isTaggedPointer()) {

uintptr_t slot = ((uintptr_t)this >> TAG_SLOT_SHIFT) & TAG_SLOT_MASK;

return objc_tag_classes[slot];

}

return ISA();

}

inline Class

objc_object::ISA()

{

assert(!isTaggedPointer());

return (Class)(isa.bits & ISA_MASK);

}

/// 类方法,沿着继承链,去判定isa(类对象isa是元类)和参数是否相等

+ (BOOL)isKindOfClass:(Class)cls {

for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {

if (tcls == cls) return YES;

}

return NO;

}

/// 实例方法,沿着继承链,去判定isa(实例对象isa是类)和参数是否相等

- (BOOL)isKindOfClass:(Class)cls {

for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {

if (tcls == cls) return YES;

}

return NO;

}

/// 类方法,判定isa(元类)和参数是否相等

+ (BOOL)isMemberOfClass:(Class)cls {

return self->ISA() == cls;

}

/// 实例方法,判定isa(类)和参数是否相等

- (BOOL)isMemberOfClass:(Class)cls {

return [self class] == cls;

}

总结:

object_getClass(obj)返回的是obj的isa指针; [obj class]则分两种情况: obj为实例对象

调用的是实例方法:- (Class)class,返回的obj对象中的isa指针;

obj为类对象(包括元类和根类以及根元类)

调用的是类方法:+ (Class)class,返回的结果为其本身。

参考:【iOS笔记 #3】class方法和objc_getClass方法

1.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.

判定依据

实例对象调用isKindOfClass

沿继承链获取isa(类对象),判定class与继承链上获取的isa是否有相等的

类对象调用isKindOfClass

沿继承链获取isa(元类对象),判定class与继承链上获取的isa是否有相等的

2.isMemberOfClass

是否是给定类的实例

Returns a Boolean value that indicates whether the receiver is an instance of a given class.

isMemberOfClass的源码实现是拿到自己的isa指针和自己比较,是否相等。

image.png

三 解析

1. res1


BOOL res1 = [(id)[NSObject class] isKindOfClass:(id)[NSObject class]]; // true

[NSObject class]类对象调用+(Class)class返回自身,即NSObject


/// 类方法,沿着继承链,去判定isa(类对象isa是元类)和参数是否相等

+ (BOOL)isKindOfClass:(Class)cls;

返回自身,即NSObject的isa是NSObjectMeta,不等,沿继承链查找superclass,[NSObjectMeta superclass] == NSObject(图右上角可看出),此时相等,返回true

2. res2


BOOL res2 = [(id)[NSObject class] isMemberOfClass:(id)[NSObject class]]; // false

[NSObject class]即NSObject


/// 类方法,判定isa(元类)和参数是否相等

+ (BOOL)isMemberOfClass:(Class)cls;

[NSObject class]的isa是NSObjectMeta,即NSObject != NSObjectMeta,即NSObject,所以是false

3. res3


BOOL res3 = [(id)[[NSObject new] class] isKindOfClass:(id)[NSObject class]]; // true

[NSObject new] class] == NSObject,后续分析与res1一致,所以是true

4. res4


BOOL res4 = [(id)[[NSObject new] class] isMemberOfClass:(id)[NSObject class]]; // false

[NSObject new] class] == NSObject,后续分析与res2一致,所以是false

5. res5


BOOL res5 = [(id)[NSObject new] isKindOfClass:(id)[NSObject class]]; // true

/// 实例方法,沿着继承链,去判定isa(实例对象isa是类)和参数是否相等

- (BOOL)isKindOfClass:(Class)cls;

id o = [NSObject new]; o 的calss是NSObject,[NSObject class] == NSObject,进入循环即相等,所以是true

6. res6


BOOL res6 = [(id)[NSObject new] isMemberOfClass:(id)[NSObject class]]; // true

/// 实例方法,判定isa(类)和参数是否相等

- (BOOL)isMemberOfClass:(Class)cls;

id o = [NSObject new]; o 的isa是NSObject,[NSObject class] == NSObject,进入循环即相等,所以是true

7. res7


BOOL res7 = [(id)[Test class] isKindOfClass:(id)[Test class]]; // false

[Test class] == Test


/// 类方法,沿着继承链,去判定isa(类对象isa是元类)和参数是否相等

+ (BOOL)isKindOfClass:(Class)cls;

1 -> Test的isa是TestMeta,TestMeta != Test;

2 -> 找superclass,[Test superclass] == NSObject,NSObject的isa是NSObjectMeta,NSObjectMeta != Test;

3 -> 继续找superclass,[NSObject superclass] == nil,nil != Test,所以是false

8. res8


BOOL res8 = [(id)[[Test new] class] isKindOfClass:(id)[Test class]]; // false

[Test class] == Test,[Test new] class] == Test


/// 类方法,沿着继承链,去判定isa(类对象isa是元类)和参数是否相等

+ (BOOL)isKindOfClass:(Class)cls;

1 -> Test 的isa是TestMeta,不等于Test,

2 -> Test的superclass是NSObject,NSObject的isa是NSObjectMeat,不等于Test,

3 -> NSObject的superclass是nil,不等于Test,所以是false

余下分析同理......