- 為什么說NSObject 的 isa 指針指向class對(duì)象
源碼getclass的實(shí)現(xiàn)如下
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
OC 的 Class 對(duì)象 是 objc_class 結(jié)構(gòu)體的指針
typedef struct objc_class *Class;
- 有人說Class 對(duì)象 isa 指針指向 meta class第焰,meta class 的 isa 指針指向 superClass
objc_class 結(jié)構(gòu)體定義如下,以及getMeta 的實(shí)現(xiàn):
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // 類的方法緩存表
class_data_bits_t bits; // 記錄類的屬性第租,方法列敲,protocol蚕脏,以及一系列標(biāo)識(shí)位
...
Class getMeta() {
if (isMetaClass()) return (Class)this;
else return this->ISA();
}
...
}
此說法并不完全準(zhǔn)確砌左,在objc-runtime 源碼中 objc_object 通過isa指針訪問類對(duì)象悬蔽, objc_class 通過 superclass 指針 來訪問父類的 class 對(duì)象,因?yàn)?objc_class 繼承自 objc_object奕筐,理論上也是一個(gè) object岛啸,所以泪酱,class 會(huì)有 isMetaClass 方法的判斷派殷,通過獲取 bits 中的標(biāo)識(shí)位还最,來返回是否是 metaClass 如果是,則是類對(duì)象毡惜,返回自己拓轻,否則視為object 對(duì)象,調(diào)用 objc_object 的 ISA() 方法 獲取metaClass虱黄,meta class 是名稱的指代悦即,是個(gè)方法
- 關(guān)于方法實(shí)現(xiàn)的查找和轉(zhuǎn)發(fā)過程, objc-runtime 中的實(shí)現(xiàn)細(xì)節(jié)
IMP lookUpImpOrForward(Class cls, SEL sel, id inst,
bool initialize, bool cache, bool resolver)
{
Class curClass;
IMP methodPC = nil;
Method meth;
//緩存查找
if (cache) {
methodPC = _cache_getImp(cls, sel);
if (methodPC) return methodPC;
}
// freed class 查找
if (cls == _class_getFreedObjectClass())
return (IMP) _freedHandler;
//類的方法列表中查找
{
Method meth = getMethodNoSuper_nolock(cls, sel);
if (meth) {
log_and_fill_cache(cls, meth->imp, sel, inst, cls);
imp = meth->imp;
goto done;
}
}
// 父類的cache和方法列表查找
{
unsigned attempts = unreasonableClassCount();
for (Class curClass = cls->superclass;
curClass != nil;
curClass = curClass->superclass)
{
// Halt if there is a cycle in the superclass chain.
if (--attempts == 0) {
_objc_fatal("Memory corruption in class list.");
}
// Superclass cache.
imp = cache_getImp(curClass, sel);
if (imp) {
if (imp != (IMP)_objc_msgForward_impcache) {
log_and_fill_cache(cls, imp, sel, inst, curClass);
goto done;
}
else {
break;
}
}
// Superclass method list.
Method meth = getMethodNoSuper_nolock(curClass, sel);
if (meth) {
log_and_fill_cache(cls, meth->imp, sel, inst, curClass);
imp = meth->imp;
goto done;
}
}
}
// 未找到方法的實(shí)現(xiàn),沒有找到的話橱乱,嘗試做消息轉(zhuǎn)發(fā)
if (resolver && !triedResolver) {
runtimeLock.unlockRead();
_class_resolveMethod(cls, sel, inst);
runtimeLock.read();
triedResolver = YES;
goto retry;
}
// 獲取轉(zhuǎn)發(fā)的 imp
imp = (IMP)_objc_msgForward_impcache;
cache_fill(cls, sel, imp, inst);
done:
runtimeLock.unlockRead();
return imp;
}
- 用人總結(jié) load 和 initialize 方法的區(qū)別時(shí)提到
load 是類加載到內(nèi)存時(shí)候調(diào)用, 優(yōu)先父類->子類->分類
initialize 是類第一次收到消息時(shí)候調(diào)用,優(yōu)先分類->子類->父類
寫代碼驗(yàn)證 load 方法 在main 函數(shù)執(zhí)行之前 無論是否使用到這個(gè)類辜梳,load 函數(shù)一定會(huì)被調(diào)用,無論是否有子類泳叠,子類是否也實(shí)現(xiàn)了 load 方法作瞄,load 方法都會(huì)被調(diào)用,并且 優(yōu)先父類->子類->分類危纫,
但是 initialize 是在 main 函數(shù)之后調(diào)用宗挥,同樣,調(diào)用時(shí)機(jī)在 objc-runtim 中可以找到种蝶,當(dāng)動(dòng)態(tài)運(yùn)行時(shí)契耿,一旦要訪問 一個(gè)創(chuàng)建一個(gè)類的對(duì)象object(初始化對(duì)object 需要使用 class 的一系列信息),或者訪問 class 的屬性螃征,class 的方法搪桂,只要涉及到要訪問 class 信息時(shí),都會(huì)先檢查 meta class 是否被初始化 如果沒有盯滚,則會(huì)先調(diào)用 類的 initialize 方法踢械,所以什么時(shí)候調(diào)用 initialize,由代碼決定魄藕,如果用到了class 就會(huì)調(diào)用 initialize内列,沒用到,則不會(huì)被調(diào)用背率,并不是 classA 繼承 classB 话瞧, classA 的 initialize 一定會(huì)比 classB 的 initialize 方法先調(diào)用,而是根據(jù)代碼編寫的時(shí)候退渗,先觸發(fā)了哪個(gè)類的訪問來決定移稳。寫代碼驗(yàn)證也確實(shí)可以有 父類的 initialize 比子類先調(diào)用的情況.當(dāng)一個(gè)類有N個(gè)子類的時(shí)候,任何一個(gè)子類的創(chuàng)建会油,都有可能出發(fā)c觸發(fā)父類的initialize被調(diào)用个粱,但其他子類的 initialize 卻沒有被調(diào)用。
- Copy 調(diào)用的是copyWithZone
- (id)copy
{
return [self copyFromZone: [self zone]];
}
- isKindOfClass 和 isMemberOfClass 區(qū)別
isKindOfClass 會(huì)對(duì)比父類 class
- (BOOL)isKindOf:aClass
{//會(huì)對(duì)比父類
Class cls;
for (cls = isa; cls; cls = cls->superclass)
if (cls == (Class)aClass)
return YES;
return NO;
}
- (BOOL)isMemberOf:aClass
{
return isa == (Class)aClass;
}
- strong 類型property 實(shí)現(xiàn)
void
objc_storeStrong(id *location, id obj)
{
id prev = *location;
if (obj == prev) {
return;
}
objc_retain(obj);
*location = obj;
objc_release(prev);
}
- weak 類型property 實(shí)現(xiàn)
放在weakHashTable 里了翻翩, set的時(shí)候 不會(huì) retain都许,get的時(shí)候會(huì) retain
void _object_setIvar(id obj, Ivar ivar, id value, bool assumeStrong)
{
if (!obj || !ivar || obj->isTaggedPointer()) return;
ptrdiff_t offset;
objc_ivar_memory_management_t memoryManagement;
_class_lookUpIvar(obj->ISA(), ivar, offset, memoryManagement);
if (memoryManagement == objc_ivar_memoryUnknown) {
if (assumeStrong) memoryManagement = objc_ivar_memoryStrong;
else memoryManagement = objc_ivar_memoryUnretained;
}
id *location = (id *)((char *)obj + offset);
switch (memoryManagement) {
case objc_ivar_memoryWeak: objc_storeWeak(location, value); break;
case objc_ivar_memoryStrong: objc_storeStrong(location, value); break;
case objc_ivar_memoryUnretained: *location = value; break;
case objc_ivar_memoryUnknown: _objc_fatal(“impossible”);
}
}
默認(rèn) assumeStrong 為no稻薇, 不是strong的話,走的是 unsafe_unretain
- property 的Atomic 實(shí)現(xiàn)加 os_unfair_lock 胶征,atomic 能保證塞椎,多線程讀寫屬性是安全的 , 除了讀寫加鎖之外,在 getproperty的實(shí)現(xiàn)中 調(diào)用了 objc_retain 睛低,保證 返回的對(duì)象案狠,不會(huì)被立即釋放,這也是钱雷,atomic 屬性 保證讀寫操作安全的關(guān)鍵
static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
if (offset == 0) {
object_setClass(self, newValue);
return;
}
id oldValue;
id *slot = (id*) ((char*)self + offset);
if (copy) {
newValue = [newValue copyWithZone:nil];
} else if (mutableCopy) {
newValue = [newValue mutableCopyWithZone:nil];
} else {
if (*slot == newValue) return;
newValue = objc_retain(newValue);
}
if (!atomic) {
oldValue = *slot;
*slot = newValue;
} else {
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
oldValue = *slot;
*slot = newValue;
slotlock.unlock();
}
objc_release(oldValue);
}
id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
if (offset == 0) {
return object_getClass(self);
}
// Retain release world
id *slot = (id*) ((char*)self + offset);
if (!atomic) return *slot;
// Atomic retain release world
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
id value = objc_retain(*slot);
slotlock.unlock();
// for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.
return objc_autoreleaseReturnValue(value);
}
- AssociationsManager 管理動(dòng)態(tài)運(yùn)行時(shí) 綁定 是個(gè)全局變量
void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
// retain the new value (if any) outside the lock.
ObjcAssociation old_association(0, nil);
id new_value = value ? acquireValue(value, policy) : nil;
{
AssociationsManager manager;
AssociationsHashMap &associations(manager.associations());
disguised_ptr_t disguised_object = DISGUISE(object);
if (new_value) {
// break any existing association.
AssociationsHashMap::iterator I = associations.find(disguised_object);
if (I != associations.end()) {
// secondary table exists
ObjectAssociationMap *refs = I->second;
ObjectAssociationMap::iterator j = refs->find(key);
if (j != refs->end()) {
old_association = j->second;
j->second = ObjcAssociation(policy, new_value);
} else {
(*refs)[key] = ObjcAssociation(policy, new_value);
}
} else {
// create the new association (first time).
ObjectAssociationMap *refs = new ObjectAssociationMap;
associations[disguised_object] = refs;
(*refs)[key] = ObjcAssociation(policy, new_value);
object->setHasAssociatedObjects();
}
} else {
// setting the association to nil breaks the association.
AssociationsHashMap::iterator I = associations.find(disguised_object);
if (I != associations.end()) {
ObjectAssociationMap *refs = I->second;
ObjectAssociationMap::iterator j = refs->find(key);
if (j != refs->end()) {
old_association = j->second;
refs->erase(j);
}
}
}
}
// release the old value (outside of the lock).
if (old_association.hasValue()) ReleaseValue()(old_association);
}