目录
- 前言
- class方法
- isMemberOfClass和isKindOfClass
- 实例方法分析
- 类方法分析
- 实例验证
- 总结
前言
认识这两个方法之前,首先要了解isa指向流程和继承链(【iOS】类对象的结构分析)关系,以便理解得更透彻
上经典图:

要注意的是:根类(NSObject)的元类isa是根元类,根元类的父类superclass是NSObject
class方法
实例调用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;
}
isMemberOfClass和isKindOfClass
查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@endint 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 1Person* 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 == 1BOOL res6 = [[NSObject class] isMemberOfClass: [NSObject class]];BOOL res7 = [person isMemberOfClass: [NSObject class]];
// BOOL res8 = [[Person class] isMemberOfClass: personMeta]; res8 == 1BOOL 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;
}
isMemberOfClassres1中调用的是类方法,沿着元类继承链会找到NSObject类对象res2中调用的是类方法,沿着元类继承链不会找到Person类对象res3中调用的是类方法,沿着元类继承链会找到NSObject类对象res4中调用的是类方法,沿着元类继承链会找到NSObject类对象res5中调用的是对象方法,沿着类继承链会找到NSObject类对象
isKindOfClassres6中调用的是类方法,对比的是元类对象,而传入的是类对象res7中调用的是对象方法,Person显然跟NSObject不是同一类res8中调用的是类方法,对比的是元类对象,而传入的是类对象res9中调用的是对象方法,person是Person类
上面的代码中,注释掉的res6、res8中传入的是相应的元类对象,则结果为1
总结
那张isa指向和继承链流程图很经典!很重要!
结合源码会对这两个方法理解得更透彻
再分得清这两个方法的调用者是class(类对象)还是instance(实例对象)