OC 源碼筆記

  1. 為什么說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;

  1. 有人說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è)方法

  1. 關(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;
}
  1. 用人總結(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)用。

  1. Copy 調(diào)用的是copyWithZone
- (id)copy
{
    return [self copyFromZone: [self zone]];
}
  1. 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;
}
  1. 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);
}
  1. 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

  1. 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);
}
  1. 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);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末骂铁,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子罩抗,更是在濱河造成了極大的恐慌拉庵,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件套蒂,死亡現(xiàn)場(chǎng)離奇詭異钞支,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)操刀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門烁挟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人骨坑,你說我怎么就攤上這事信夫。” “怎么了卡啰?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)警没。 經(jīng)常有香客問我匈辱,道長(zhǎng),這世上最難降的妖魔是什么杀迹? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任亡脸,我火速辦了婚禮,結(jié)果婚禮上树酪,老公的妹妹穿的比我還像新娘浅碾。我一直安慰自己,他們只是感情好续语,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布垂谢。 她就那樣靜靜地躺著,像睡著了一般疮茄。 火紅的嫁衣襯著肌膚如雪滥朱。 梳的紋絲不亂的頭發(fā)上根暑,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音徙邻,去河邊找鬼排嫌。 笑死,一個(gè)胖子當(dāng)著我的面吹牛缰犁,可吹牛的內(nèi)容都是我干的淳地。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼帅容,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼颇象!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起丰嘉,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤夯到,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后饮亏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體耍贾,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年路幸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了荐开。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡简肴,死狀恐怖晃听,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情砰识,我是刑警寧澤能扒,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站辫狼,受9級(jí)特大地震影響初斑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜膨处,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一见秤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧真椿,春花似錦鹃答、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至狞换,卻和暖如春避咆,著一層夾襖步出監(jiān)牢的瞬間舟肉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工查库, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留路媚,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓樊销,卻偏偏與公主長(zhǎng)得像整慎,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子围苫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 我們常常會(huì)聽說 Objective-C 是一門動(dòng)態(tài)語(yǔ)言裤园,那么這個(gè)「動(dòng)態(tài)」表現(xiàn)在哪呢?我想最主要的表現(xiàn)就是 Obje...
    Ethan_Struggle閱讀 2,176評(píng)論 0 7
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,089評(píng)論 1 32
  • 轉(zhuǎn)載:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麥子閱讀 728評(píng)論 0 2
  • 本文轉(zhuǎn)載自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex閱讀 748評(píng)論 0 1
  • 本文詳細(xì)整理了 Cocoa 的 Runtime 系統(tǒng)的知識(shí)剂府,它使得 Objective-C 如虎添翼拧揽,具備了靈活的...
    lylaut閱讀 792評(píng)論 0 4