在OC的類結構中,存在這樣的結構:
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
class_rw_t *data() {
return bits.data();
}
...
...
}
類結構中包含了class_data_bits_t結構,這個結構實際上上是由一個指針(class_rw_t *)和一些關於類初始化狀態的的標識組成.可以通過
#if !__LP64__
...
// data pointer
#define FAST_DATA_MASK 0xfffffffcUL
...
#elif 1
...
#define FAST_DATA_MASK 0x00007ffffffffff8UL
...
#else
...
#define FAST_DATA_MASK 0x00007ffffffffff8UL
...
#endif
class_rw_t* data() {
return (class_rw_t *)(bits & FAST_DATA_MASK);
//FAST_DATA_MASK的定義跟ISA_MASK很相近
}
來獲取類結構中的class_rw_t指針.而class_rw_t結構中又包含了一個const class_ro_t *類型的指針實現,那麼class_rw_t和class_ro_t這兩個看起來只有一個字符差距的結構有什麼不一樣呢?
成員變量的不同
包含基本成員變量的不同
struct class_ro_t {
uint32_t flags; // class_rw_t也有
uint32_t instanceStart; //class_rw_t沒有
uint32_t instanceSize;//class_rw_t沒有
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout;
const char * name;
method_list_t * baseMethodList;//與class_rw_t中的methods對應
protocol_list_t * baseProtocols;//與class_rw_t中的protocols對應
const ivar_list_t * ivars; //class_rw_t沒有
const uint8_t * weakIvarLayout;//class_rw_t沒有
property_list_t *baseProperties; //與class_rw_t中的properties對應
/*
class_rw_t多出了以下成員變量
Class firstSubclass;
Class nextSiblingClass;
char *demangledName;
*/
...
...
}
對比發現,class_ro_t結構中與class_rw_t對應的的主要成員變量都使用了base做區分,說明class_ro_t的結構更加貼近類本身的結構,class_rw_t像是類拓展出來的.
可變性不同
struct class_rw_t {
...
const class_ro_t *ro;
...
}
在關於類的實現中,幾乎所有引用到class_ro_t變量的地方都是使用了const關鍵字做修飾,更像是一個靜態不願意被外界修改的屬性;而引用到class_rw_t變量就沒有這樣的限制.
作用不同
使用objc源碼進行調試,在main中創建對象
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSObject *obj = [[NSObject alloc] init];
}
}
並在setData處進行斷點:
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
class_rw_t *data() {
return bits.data();
}
void setData(class_rw_t *newData) {
bits.setData(newData); //在此處下斷點
}
...
...
}
然後會發現如下調用:
發現在_read_images之後就調用了realizeClassWithoutSwift函數:
ro = (const class_ro_t *)cls->data();
if (ro->flags & RO_FUTURE) {
// This was a future class. rw data is already allocated.
rw = cls->data();
ro = cls->data()->ro;
cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
} else {
// Normal class. Allocate writeable class data.
rw = (class_rw_t *)calloc(sizeof(class_rw_t), 1);
rw->ro = ro;
rw->flags = RW_REALIZED|RW_REALIZING;
cls->setData(rw);
}
而此時ro已經是一個實例化之後的class_ro_t *指針,所以class_ro_t *是在類編譯時就已經完成初始化賦值且不可被改變的.而class_rw_t結構則是可以通過方法進行修改.例如:
static SEL *
addMethods(Class cls, const SEL *names, const IMP *imps, const char **types,
uint32_t count, bool replace, uint32_t *outFailedCount)
{
runtimeLock.assertLocked();
assert(names);
assert(imps);
assert(types);
assert(cls->isRealized());
...
...
if (newlist->count > 0) {
// fixme resize newlist because it may have been over-allocated above.
// Note that realloc() alone doesn't work due to ptrauth.
method_t::SortBySELAddress sorter;
std::stable_sort(newlist->begin(), newlist->end(), sorter);
prepareMethodLists(cls, &newlist, 1, NO, NO);
cls->data()->methods.attachLists(&newlist, 1);
flushCaches(cls);
} else {
// Attaching the method list to the class consumes it. If we don't
// do that, we have to free the memory ourselves.
free(newlist);
}
if (outFailedCount) *outFailedCount = failedCount;
return failedNames;
}
所以可以理解爲class_ro_t存儲的是類在編譯期就已經確定的特性,而class_rw_t則是提供在運行時進行類延展的能力.
需要注意的是,通過運行時使用
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) {
_object_set_associative_reference(object, (void *)key, value, policy);
}
來爲對象添加屬性並不是通過class_rw_t來實現的,而是通過全局維護的hashMap來實現的.