文章目录
前言
在上一篇中已经知道类的结构体为
struct objc_class : objc_object {
// 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,第二个存放的父类,第三个从字面理解是缓存,第四个从上面的注释可以得知,bits里主要的信息就是class_rw_t *加上一些自定义rr/alloc标记。
那么方法、属性、成员变量等信息存在了哪里?
一、bits有什么?方法?属性?成员变量?
1 class_data_bits_t
struct class_data_bits_t {
friend objc_class;
// Values are the FAST_ flags above.
uintptr_t bits;
......
class_rw_t* data() const {
return (class_rw_t *)(bits & FAST_DATA_MASK);
}
void setData(class_rw_t *newData)
{
ASSERT(!data() || (newData->flags & (RW_REALIZING | RW_FUTURE)));
// Set during realization or construction only. No locking needed.
// Use a store-release fence because there may be concurrent
// readers of data and data's contents.
uintptr_t newBits = (bits & ~FAST_DATA_MASK) | (uintptr_t)newData;
atomic_thread_fence(memory_order_release);
bits = newBits;
}
// Get the class's ro data, even in the presence of concurrent realization.
// fixme this isn't really safe without a compiler barrier at least
// and probably a memory barrier when realizeClass changes the data field
const class_ro_t *safe_ro() {
class_rw_t *maybe_rw = data();
if (maybe_rw->flags & RW_REALIZED) {
// maybe_rw is rw
return maybe_rw->ro();
} else {
// maybe_rw is actually ro
return (class_ro_t *)maybe_rw;
}
}
.......
}
通过friend关键字把objc_class设为了友元结构体,从而可以访问其私有内容。
class_data_bits_t中只有一个bits变量,从注释中得知里面存着以FAST_开头的定义的flags,例如FAST_HAS_DEFAULT_RR、FAST_CACHE_HAS_CXX_DTOR等等。class_data_bits_t结构体里并没有看到方法、属性相关的内容,但是通过data()方法可以看到bits变量中还存有一个class_rw_t类型的data指针。
2 class_rw_t
struct class_rw_t {
......
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 *>()->methods;
} else {
return method_array_t{
v.get<const class_ro_t *>()->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 *>()->properties;
} else {
return property_array_t{
v.get<const class_ro_t *>()->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 *>()->protocols;
} else {
return protocol_array_t{
v.get<const class_ro_t *>()->baseProtocols};
}
}
};
在class_rw_t结构体中我们找到了methods()、properties()、protocols()方法,从methods()方法体中看到它有两种返回情况,一种是class_rw_ext_t,一种是class_ro_t。
2.1 class_rw_ext_t
struct class_rw_ext_t {
const class_ro_t *ro; //存放的就是ro的内容
method_array_t methods; //存放ro中的方法+动态添加的方法
property_array_t properties;
protocol_array_t protocols;
char *demangledName;
uint32_t version; //元类7,非元类0
};
2.2 class_ro_t
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout;
const char * name;
method_list_t * baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
// This field exists only when RO_HAS_SWIFT_INITIALIZER is set.
_objc_swiftMetadataInitializer __ptrauth_objc_method_list_imp _swiftMetadataInitializer_NEVER_USE[0];
_objc_swiftMetadataInitializer swiftMetadataInitializer() const {
if (flags & RO_HAS_SWIFT_INITIALIZER) {
return _swiftMetadataInitializer_NEVER_USE[0];
} else {
return nil;
}
}
method_list_t *baseMethods() const {
return baseMethodList;
}
class_ro_t *duplicate() const {
if (flags & RO_HAS_SWIFT_INITIALIZER) {
size_t size = sizeof(*this) + sizeof(_swiftMetadataInitializer_NEVER_USE[0]);
class_ro_t *ro = (class_ro_t *)memdup(this, size);
ro->_swiftMetadataInitializer_NEVER_USE[0] = this->_swiftMetadataInitializer_NEVER_USE[0];
return ro;
} else {
size_t size = sizeof(*this);
class_ro_t *ro = (class_ro_t *)memdup(this, size);
return ro;
}
}
};
可以在这里面看到有baseMethodList、ivars、baseProperties等信息,那么方法、成员变量、属性到底存没存在这些地方?如果是存在这些地方,class_rw_ext_t和class_ro_t中存的方法、属性、协议信息又有什么区别?我们通过代码去验证一下。
二、验证
@interface TestA : NSObject
@property(nonatomic, copy) NSString *nickname;
- (void)sayHello;
+ (void)sayAny;
@end
@implementation TestA
- (void)sayHello {
}
+ (void)sayAny {
}
@end
@interface TestA(SayU)
- (void)sayU;
@end
@implementation TestA(SayU)
- (void)sayU {
}
@end