赞
踩
认识这两个方法之前,首先要了解isa
指向流程和继承链(【iOS】类对象的结构分析)关系,以便理解得更透彻
上经典图:
要注意的是:根类(NSObject)的元类isa
是根元类,根元类的父类superclass
是NSObject
实例调用class
方法就是获取isa
所指:
- (Class)class {
return object_getClass(self);
}
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
类调用class
方法就是返回本身Class
:
typedef struct objc_class *Class;
+ (Class)class {
return self;
}
查objc4
源码
+ (BOOL)isMemberOfClass:(Class)cls { return self->ISA() == cls; } - (BOOL)isMemberOfClass:(Class)cls { return [self class] == cls; } + (BOOL)isKindOfClass:(Class)cls { for (Class tcls = self->ISA(); tcls; tcls = tcls->getSuperclass()) { if (tcls == cls) return YES; } return NO; } - (BOOL)isKindOfClass:(Class)cls { for (Class tcls = [self class]; tcls; tcls = tcls->getSuperclass()) { if (tcls == cls) return YES; } return NO; }
- (BOOL)isMemberOfClass:(Class)cls
:
此方法用于判断self
(调用者)类型与cls
(指定类)是否是同一个类,是就返回YES
,否则返回NO
。因为每个类对象在内存中只存在一份,所以可以用==
判断
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
- (BOOL)isKindOfClass:(Class)cls
:
此方法用于判断self
(调用者)类型与cls
(指定类或者其父类)是否是同一个类,是就返回YES
,否则就沿着继承链向上查找,只要有一个类与cls
使用一个类,就返回YES
,如果直到NSObject
还没有找到,再向上就为nil
,返回NO
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}
类方法的调用者是Class
类对象,按照isa
指向,对比的应该是meta-class
元类对象
+ (BOOL)isMemberOfClass:(Class)cls
:
此方法判断self
(调用者)的isa
(元类)是否是指定元类(元类也是Class类型)
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
+ (BOOL)isKindOfClass:(Class)cls
:
此方法实现与其对象方法的实现类似,只是对比的是元类及元类的继承链
判断self
(调用者)的isa
(元类)是否是指定类的元类或者其父类的元类,是就返回YES
,否则就沿着继承链向上找到根元类
,最后如果沿着superclass
直到NSObject
还没找到,再向上就为nil
,返回NO
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = self->ISA(); tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}
下面通过调用上面的方法,来验证以上的分析:
#import <Foundation/Foundation.h> #import <objc/runtime.h> @interface Person : NSObject @end @implementation Person @end int main(int argc, const char * argv[]) { @autoreleasepool { BOOL res1 = [[NSObject class] isKindOfClass: [NSObject class]]; BOOL res2 = [[Person class] isKindOfClass: [Person class]]; BOOL res3 = [[NSString class] isKindOfClass: [NSObject class]]; NSLog(@"%d %d %d", res1, res2, res3); // 1 0 1 Person* person = [[Person alloc] init]; BOOL res4 = [[Person class] isKindOfClass: [NSObject class]]; BOOL res5 = [person isKindOfClass: [NSObject class]]; NSLog(@"%d %d", res4, res5); // 1 1 // 获取一个类的元类的两种方式 // Class objectMeta = objc_getMetaClass("NSObject"); Class objectMeta = object_getClass([NSObject class]); // Class personMeta = objc_getClass("Person"); Class personMeta = object_getClass([Person class]); // BOOL res6 = [[NSObject class] isMemberOfClass: objectMeta]; res6 == 1 BOOL res6 = [[NSObject class] isMemberOfClass: [NSObject class]]; BOOL res7 = [person isMemberOfClass: [NSObject class]]; // BOOL res8 = [[Person class] isMemberOfClass: personMeta]; res8 == 1 BOOL res8 = [[Person class] isMemberOfClass: [NSObject class]]; BOOL res9 = [person isMemberOfClass: [Person class]]; NSLog(@"%d %d %d %d" , res6, res7, res8, res9); // 0 0 0 1 } return 0; }
isMemberOfClass
res1
中调用的是类方法,沿着元类继承链会找到NSObject
类对象res2
中调用的是类方法,沿着元类继承链不会找到Person
类对象res3
中调用的是类方法,沿着元类继承链会找到NSObject
类对象res4
中调用的是类方法,沿着元类继承链会找到NSObject
类对象res5
中调用的是对象方法,沿着类继承链会找到NSObject
类对象isKindOfClass
res6
中调用的是类方法,对比的是元类对象,而传入的是类对象res7
中调用的是对象方法,Person
显然跟NSObject
不是同一类res8
中调用的是类方法,对比的是元类对象,而传入的是类对象res9
中调用的是对象方法,person
是Person
类上面的代码中,注释掉的res6
、res8
中传入的是相应的元类对象,则结果为1
那张isa
指向和继承链流程图很经典!很重要!
结合源码会对这两个方法理解得更透彻
再分得清这两个方法的调用者是class
(类对象)还是instance
(实例对象)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。