OC對象原理探究

1.alloc 方法到底干了什么?


先來看一段代碼

Person *p1 = [Person alloc]; 
Person *p2 = [p1 init];
Person *p3 = [p1 init];
NSLog(@"%@ --- %p",p1,&p1);
NSLog(@"%@ --- %p",p2,&p2);
NSLog(@"%@ --- %p",p3,&p3);
<Person: 0x10103be00> --- 0x7ffeefbff4b0
<Person: 0x10103be00> --- 0x7ffeefbff4a0
<Person: 0x10103be00> --- 0x7ffeefbff4a8
  • 這里通過打印結(jié)果發(fā)現(xiàn) p1, p2, p3 的內(nèi)存地址是相同的說明它們指向的是同一堆區(qū)內(nèi)存區(qū)域,但是指針地址不同
  • 如圖所示:


    內(nèi)存分布.png

2.從 OC 源碼的跟蹤 alloc


從源碼直接 command + click 查看 alloc 方法

+ (id)alloc {
    return _objc_rootAlloc(self);
}

_objc_rootAlloc 方法里面調(diào)用了 callAlloc方法

id  _objc_rootAlloc(Class cls) {
    return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}

callAlloc方法里面調(diào)用了_class_createInstanceFromZone

// Call [cls alloc] or [cls allocWithZone:nil], with appropriate 
// shortcutting optimizations.
static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
#if __OBJC2__
    if (slowpath(checkNil && !cls)) return nil;
    if (fastpath(!cls->ISA()->hasCustomAWZ())) {
        return _objc_rootAllocWithZone(cls, nil);
    }
#endif

    // No shortcuts available.
    if (allocWithZone) {
        return ((id(*)(id, SEL, struct _NSZone *))objc_msgSend)(cls, @selector(allocWithZone:), nil);
    }
    return ((id(*)(id, SEL))objc_msgSend)(cls, @selector(alloc));
}

這里面調(diào)用了_class_createInstanceFromZone方法

NEVER_INLINE
id  _objc_rootAllocWithZone(Class cls, malloc_zone_t *zone __unused)
{
    // allocWithZone under __OBJC2__ ignores the zone parameter
    return _class_createInstanceFromZone(cls, 0, nil,
                                         OBJECT_CONSTRUCT_CALL_BADALLOC);
}

最關(guān)鍵就在_class_createInstanceFromZone方法里面

static ALWAYS_INLINE id
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,
                              int construct_flags = OBJECT_CONSTRUCT_NONE,
                              bool cxxConstruct = true,
                              size_t *outAllocatedSize = nil)
{
    ASSERT(cls->isRealized());

    // Read class's info bits all at once for performance
    bool hasCxxCtor = cxxConstruct && cls->hasCxxCtor();
    bool hasCxxDtor = cls->hasCxxDtor();
    bool fast = cls->canAllocNonpointer();
    size_t size;
    // 1:要開辟多少內(nèi)存
    size = cls->instanceSize(extraBytes);
    if (outAllocatedSize) *outAllocatedSize = size;

    id obj;
    if (zone) {
        obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
    } else {
        // 2;怎么去申請內(nèi)存
        obj = (id)calloc(1, size);
    }
    if (slowpath(!obj)) {
        if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
            return _objc_callBadAllocHandler(cls);
        }
        return nil;
    }

    // 3: 初始化 isa 關(guān)聯(lián)類?
    if (!zone && fast) {
        obj->initInstanceIsa(cls, hasCxxDtor);
    } else {
        // Use raw pointer isa on the assumption that they might be
        // doing something weird with the zone or RR.
        obj->initIsa(cls);
    }

    if (fastpath(!hasCxxCtor)) {
        return obj;
    }

    construct_flags |= OBJECT_CONSTRUCT_FREE_ONFAILURE;
    return object_cxxConstructFromClass(obj, cls, construct_flags);
}

這里面主要做三件事情

1.計算需要開辟的內(nèi)存空間大小 size = cls->instanceSize(extraBytes);
2.開辟內(nèi)存 obj = (id)calloc(1, size);
3.實例化 isa obj->initIsa(cls);

下面是總結(jié)的alloc方法的實際流程圖

流程圖.png

3.發(fā)現(xiàn)問題


1.為什么一開始我們調(diào)用的 alloc 的方法驴娃,底層卻調(diào)用的是 objc_alloc

這里是因為在 llvm 源碼中系統(tǒng)在編譯期間就對 alloc 方法做了替換

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末贯钩,一起剝皮案震驚了整個濱河市来惧,隨后出現(xiàn)的幾起案子翩腐,更是在濱河造成了極大的恐慌忿墅,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,222評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件懈叹,死亡現(xiàn)場離奇詭異最冰,居然都是意外死亡,警方通過查閱死者的電腦和手機楷力,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,455評論 3 385
  • 文/潘曉璐 我一進店門喊式,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人萧朝,你說我怎么就攤上這事岔留。” “怎么了检柬?”我有些...
    開封第一講書人閱讀 157,720評論 0 348
  • 文/不壞的土叔 我叫張陵献联,是天一觀的道長。 經(jīng)常有香客問我何址,道長里逆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,568評論 1 284
  • 正文 為了忘掉前任用爪,我火速辦了婚禮原押,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘偎血。我一直安慰自己诸衔,他們只是感情好,可當我...
    茶點故事閱讀 65,696評論 6 386
  • 文/花漫 我一把揭開白布颇玷。 她就那樣靜靜地躺著笨农,像睡著了一般。 火紅的嫁衣襯著肌膚如雪帖渠。 梳的紋絲不亂的頭發(fā)上谒亦,一...
    開封第一講書人閱讀 49,879評論 1 290
  • 那天,我揣著相機與錄音空郊,去河邊找鬼份招。 笑死,一個胖子當著我的面吹牛狞甚,可吹牛的內(nèi)容都是我干的脾还。 我是一名探鬼主播,決...
    沈念sama閱讀 39,028評論 3 409
  • 文/蒼蘭香墨 我猛地睜開眼入愧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起棺蛛,我...
    開封第一講書人閱讀 37,773評論 0 268
  • 序言:老撾萬榮一對情侶失蹤怔蚌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后旁赊,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體桦踊,經(jīng)...
    沈念sama閱讀 44,220評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,550評論 2 327
  • 正文 我和宋清朗相戀三年终畅,在試婚紗的時候發(fā)現(xiàn)自己被綠了籍胯。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,697評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡离福,死狀恐怖杖狼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情妖爷,我是刑警寧澤蝶涩,帶...
    沈念sama閱讀 34,360評論 4 332
  • 正文 年R本政府宣布,位于F島的核電站絮识,受9級特大地震影響绿聘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜次舌,卻給世界環(huán)境...
    茶點故事閱讀 40,002評論 3 315
  • 文/蒙蒙 一熄攘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧彼念,春花似錦挪圾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,782評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至酱吝,卻和暖如春也殖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背务热。 一陣腳步聲響...
    開封第一講書人閱讀 32,010評論 1 266
  • 我被黑心中介騙來泰國打工忆嗜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人崎岂。 一個月前我還...
    沈念sama閱讀 46,433評論 2 360
  • 正文 我出身青樓捆毫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親冲甘。 傳聞我的和親對象是個殘疾皇子绩卤,可洞房花燭夜當晚...
    茶點故事閱讀 43,587評論 2 350