类的原理分析
我们首先创建一个类LKPerson,然后
LKPerson *p = [LKPerson alloc];
进入llvm调试,打印当前对象地址
0x01000001000082e9是isa的地址,可以看到去除掩码之后,地址指向类LKPerson,
尝试打印类LKPerson的地址,得到
发现类的
isa仍然指向的是类LKPerson,继续打印
发现这个类的
isa指向了NSObject,接着打印
发现
NSObject的isa指向自己。
这里为什么会有两个LKPerson,是否一个类可以有多个指针地址,继续尝试
Class class1 = [LKPerson class];
Class class2 = [LKPerson alloc].class;
Class class3 = object_getClass([LKPerson alloc]);
Class class4 = [LKPerson alloc].class;
NSLog(@"\n%p-\n%p-\n%p-\n%p",class1,class2,class3,class4);
输出结果
发现类的地址都一样,那么为什么会有两个不一样的地址都指向
LKPerson,利用MachOView工具打开Products文件,搜索LKPerson,可以看到
系统自己创建了一个
METACLASS。
总结 对象的isa指向类,类的isa指向元类,元类的isa指向根元类NSObject,根元类isa指向根元类NSObject。
类的继承链
创建一个类LKTeacher继承自LKPerson
Class psClass = class_getSuperclass(LKPerson.class);//LKPerson的父类
Class pMetaClass = object_getClass(LKPerson.class);//LKPerson元类
Class psuperClass = class_getSuperclass(pMetaClass);//LKPerson元类的父类
NSLog(@"LKPerson类的父类 %@ - %p",psClass,psClass);
NSLog(@"LKPerson元类 %@ - %p",pMetaClass,pMetaClass);
NSLog(@"LKPerson元类的父类 %@ - %p",psuperClass,psuperClass);
Class tMetaClass = object_getClass(LKTeacher.class);//LKTeacher元类
Class tsuperClass = class_getSuperclass(tMetaClass);//LKTeacher元类的父类
NSLog(@"LKTeacher元类的父类 %@ - %p",tsuperClass,tsuperClass);
Class nsuperClass = class_getSuperclass(NSObject.class);//NSObject的父类
NSLog(@"NSObject的父类%@ - %p",nsuperClass,nsuperClass);
Class nMetaClass = object_getClass(NSObject.class);// 根元类NSObject
Class rnsuperClass = class_getSuperclass(nMetaClass);//根元类NSObject的父类
NSLog(@"NSObject类%@ - %p",NSObject.class,NSObject.class);
NSLog(@"NSObject元类%@ - %p",nMetaClass,nMetaClass);
NSLog(@"NSObject元类的父类%@ - %p",rnsuperClass,rnsuperClass);
输出结果
可以看到
LKPerson元类的父类是根元类NSObject,LKTeacher元类的父类是LKPerson的元类,NSObject的父类为nil,NSObject的元类的父类为NSObject。
总结 类->父类->NSObject->nil 元类->父类的元类->根元类NSObject->NSObject->nil
isa流程图
根据源码和llvm分析类的结构
新建一个类LKPerson
@interface LKPerson : NSObject{
NSString *subject;
}
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *hobby;
@property (nonatomic, assign) int count;
- (void)sayNB;
- (void)sayNB:(NSString *)str count:(int)count;
+ (void)say666;
@end
类的本质是一个结构体objc_class
struct objc_class : objc_object {
objc_class(const objc_class&) = delete;
objc_class(objc_class&&) = delete;
void operator=(const objc_class&) = delete;
void operator=(objc_class&&) = delete;
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
//后面省略
}
可以看到第一个为isa为8字节,superclass为8字节,
struct cache_t {
private:
explicit_atomic<uintptr_t> _bucketsAndMaybeMask;
union {
struct {
explicit_atomic<mask_t> _maybeMask;
#if __LP64__
uint16_t _flags;
#endif
uint16_t _occupied;
};
explicit_atomic<preopt_cache_t *> _originalPreoptCache;
};
//后面省略,结构体大小只与成员变量有关,static存储在全局区,所以省略
}
从上面可以看出cache_t为8+8=16字节。
利用llvm打印,得到LKPerson首地址
偏移8+8+16个字节后,得到我们想要的
bits,打印
查看
class_data_bits_t,可以看到data方法
class_rw_t* data() const {
return (class_rw_t *)(bits & FAST_DATA_MASK);
}
查看class_rw_t
const class_ro_t *ro() const {
auto v = get_ro_or_rwe();
if (slowpath(v.is<class_rw_ext_t *>())) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro;
}
return v.get<const class_ro_t *>(&ro_or_rw_ext);
}
void set_ro(const class_ro_t *ro) {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro = ro;
} else {
set_ro_or_rwe(ro);
}
}
const method_array_t methods() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->methods;
} else {
return method_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseMethods()};
}
}
const property_array_t properties() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->properties;
} else {
return property_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProperties};
}
}
const protocol_array_t protocols() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->protocols;
} else {
return protocol_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProtocols};
}
}
打印
可以看到,声明的属性都存放在
properties里面,但是subject并不在里面。
接下来我们试着打印方法
用同样的方法打印不出来,查看
method_t
struct big {
SEL name;
const char *types;
MethodListIMP imp;
};
private:
bool isSmall() const {
return ((uintptr_t)this & 1) == 1;
}
// The representation of a "small" method. This stores three
// relative offsets to the name, types, and implementation.
struct small {
// The name field either refers to a selector (in the shared
// cache) or a selref (everywhere else).
RelativePointer<const void *> name;
RelativePointer<const char *> types;
RelativePointer<IMP> imp;
bool inSharedCache() const {
return (CONFIG_SHARED_CACHE_RELATIVE_DIRECT_SELECTORS &&
objc::inSharedCache((uintptr_t)this));
}
};
可以看到big和small两个结构体,还可以找到
objc_method_description *getDescription() const {
return isSmall() ? getSmallDescription() : (struct objc_method_description *)this;
}
打印结果
可以看到,
get,set方法,以及实例方法,但是并没有类方法。
探索变量以及类方法
查看ro,找到ivars打印
类方法存储在元类里面