iOS運行時(1)——類(Class)和對象(id)

struct objc_class {
    struct objc_class *isa;
};
struct objc_object {
    struct objc_class *isa;
};
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class; //類  (class object)
/// A pointer to an instance of a class.
typedef struct objc_object *id;   //對象 (instance of class)

objc_class結(jié)構(gòu)體內(nèi),有一個Class類型的變量叫isa拼窥,由上面可以知道Class是一個objc_class指針抛人,因此isa是一個objc_class指針,通常如果在一個objc_object(下面會說到)中糜芳,也會有一個isa指針飒货,指向的是這個對象所對應(yīng)的類(objc_class)。 如果是在objc_class中的isa指針峭竣,指向的則是這個類的元類(metaClass)

創(chuàng)建類

image.png
image.png
struct objc_object {
private:
    isa_t isa;

public:

    // ISA() assumes this is NOT a tagged pointer object
    Class ISA();

    // getIsa() allows this to be a tagged pointer object
    Class getIsa();

    // initIsa() should be used to init the isa of new objects only.
    // If this object already has an isa, use changeIsa() for correctness.
    // initInstanceIsa(): objects with no custom RR/AWZ
    // initClassIsa(): class objects
    // initProtocolIsa(): protocol objects
    // initIsa(): other objects
    void initIsa(Class cls /*nonpointer=false*/);
    void initClassIsa(Class cls /*nonpointer=maybe*/);
    void initProtocolIsa(Class cls /*nonpointer=maybe*/);
    void initInstanceIsa(Class cls, bool hasCxxDtor);

    // changeIsa() should be used to change the isa of existing objects.
    // If this is a new object, use initIsa() for performance.
    Class changeIsa(Class newCls);

    bool hasNonpointerIsa();
    bool isTaggedPointer();
    bool isBasicTaggedPointer();
    bool isExtTaggedPointer();
    bool isClass();

    // object may have associated objects?
    bool hasAssociatedObjects();
    void setHasAssociatedObjects();

    // object may be weakly referenced?
    bool isWeaklyReferenced();
    void setWeaklyReferenced_nolock();

    // object may have -.cxx_destruct implementation?
    bool hasCxxDtor();

    // Optimized calls to retain/release methods
    id retain();
    void release();
    id autorelease();

    // Implementations of retain/release methods
    id rootRetain();
    bool rootRelease();
    id rootAutorelease();
    bool rootTryRetain();
    bool rootReleaseShouldDealloc();
    uintptr_t rootRetainCount();

    // Implementation of dealloc methods
    bool rootIsDeallocating();
    void clearDeallocating();
    void rootDealloc();

private:
    void initIsa(Class newCls, bool nonpointer, bool hasCxxDtor);

    // Slow paths for inline control
    id rootAutorelease2();
    bool overrelease_error();

#if SUPPORT_NONPOINTER_ISA
    // Unified retain count manipulation for nonpointer isa
    id rootRetain(bool tryRetain, bool handleOverflow);
    bool rootRelease(bool performDealloc, bool handleUnderflow);
    id rootRetain_overflow(bool tryRetain);
    bool rootRelease_underflow(bool performDealloc);

    void clearDeallocating_slow();

    // Side table retain count overflow for nonpointer isa
    void sidetable_lock();
    void sidetable_unlock();

    void sidetable_moveExtraRC_nolock(size_t extra_rc, bool isDeallocating, bool weaklyReferenced);
    bool sidetable_addExtraRC_nolock(size_t delta_rc);
    size_t sidetable_subExtraRC_nolock(size_t delta_rc);
    size_t sidetable_getExtraRC_nolock();
#endif

    // Side-table-only retain count
    bool sidetable_isDeallocating();
    void sidetable_clearDeallocating();

    bool sidetable_isWeaklyReferenced();
    void sidetable_setWeaklyReferenced_nolock();

    id sidetable_retain();
    id sidetable_retain_slow(SideTable& table);

    uintptr_t sidetable_release(bool performDealloc = true);
    uintptr_t sidetable_release_slow(SideTable& table, bool performDealloc = true);

    bool sidetable_tryRetain();

    uintptr_t sidetable_retainCount();
#if DEBUG
    bool sidetable_present();
#endif
};

objc_class

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;

object_getClass源碼:

Class object_getClass(id obj)
{
    if (obj) return obj->getIsa();
    else return Nil;
}

通過clang Dog.m

clang -rewrite-objc Dog.m
#import <Foundation/Foundation.h>

@interface Animal : NSObject
@end

@implementation Animal
@end

@interface Dog : Animal {
    int age;
    NSString *name;
}
- (void)instanceFun;
+ (void)classFun;
@end

@implementation Dog
- (void)instanceFun {
}
+ (void)classFun {
}
@end

extern "C" __declspec(dllexport) struct _class_t OBJC_METACLASS_$_Animal;
extern "C" __declspec(dllimport) struct _class_t OBJC_METACLASS_$_NSObject;

extern "C" __declspec(dllexport) struct _class_t OBJC_METACLASS_$_Dog __attribute__ ((used, section ("__DATA,__objc_data"))) = {
    0, // &OBJC_METACLASS_$_NSObject,
    0, // &OBJC_METACLASS_$_Animal,
    0, // (void *)&_objc_empty_cache,
    0, // unused, was (void *)&_objc_empty_vtable,
    &_OBJC_METACLASS_RO_$_Dog,
};

extern "C" __declspec(dllexport) struct _class_t OBJC_CLASS_$_Animal;

extern "C" __declspec(dllexport) struct _class_t OBJC_CLASS_$_Dog __attribute__ ((used, section ("__DATA,__objc_data"))) = {
    0, // &OBJC_METACLASS_$_Dog,
    0, // &OBJC_CLASS_$_Animal,
    0, // (void *)&_objc_empty_cache,
    0, // unused, was (void *)&_objc_empty_vtable,
    &_OBJC_CLASS_RO_$_Dog,
};
static void OBJC_CLASS_SETUP_$_Dog(void ) {
    OBJC_METACLASS_$_Dog.isa = &OBJC_METACLASS_$_NSObject;
    OBJC_METACLASS_$_Dog.superclass = &OBJC_METACLASS_$_Animal;
    OBJC_METACLASS_$_Dog.cache = &_objc_empty_cache;
    OBJC_CLASS_$_Dog.isa = &OBJC_METACLASS_$_Dog;
    OBJC_CLASS_$_Dog.superclass = &OBJC_CLASS_$_Animal;
    OBJC_CLASS_$_Dog.cache = &_objc_empty_cache;
}

static struct _class_ro_t _OBJC_METACLASS_RO_$_Dog __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    1, sizeof(struct _class_t), sizeof(struct _class_t), 
    (unsigned int)0, 
    0, 
    "Dog",
    (const struct _method_list_t *)&_OBJC_$_CLASS_METHODS_Dog,
    0, 
    0, 
    0, 
    0, 
};

static struct _class_ro_t _OBJC_CLASS_RO_$_Dog __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    0, __OFFSETOFIVAR__(struct Dog, age), sizeof(struct Dog_IMPL), 
    (unsigned int)0, 
    0, 
    "Dog",
    (const struct _method_list_t *)&_OBJC_$_INSTANCE_METHODS_Dog,
    0, 
    (const struct _ivar_list_t *)&_OBJC_$_INSTANCE_VARIABLES_Dog,
    0, 
    0, 
};

extern "C" __declspec(dllexport) struct _class_t OBJC_METACLASS_$_Animal;
extern "C" __declspec(dllimport) struct _class_t OBJC_METACLASS_$_NSObject;

extern "C" __declspec(dllexport) struct _class_t OBJC_METACLASS_$_Dog __attribute__ ((used, section ("__DATA,__objc_data"))) = {
    0, // &OBJC_METACLASS_$_NSObject,
    0, // &OBJC_METACLASS_$_Animal,
    0, // (void *)&_objc_empty_cache,
    0, // unused, was (void *)&_objc_empty_vtable,
    &_OBJC_METACLASS_RO_$_Dog,
};

實例方法和實例變量應(yīng)該被加到類中塘辅。類方法被加到元類中。

static struct /*_method_list_t*/ {
    unsigned int entsize;  // sizeof(struct _objc_method)
    unsigned int method_count;
    struct _objc_method method_list[1];
} _OBJC_$_INSTANCE_METHODS_Dog __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    sizeof(_objc_method),
    1,
    {{(struct objc_selector *)"instanceFun", "v16@0:8", (void *)_I_Dog_instanceFun}}
};

static struct /*_method_list_t*/ {
    unsigned int entsize;  // sizeof(struct _objc_method)
    unsigned int method_count;
    struct _objc_method method_list[1];
} _OBJC_$_CLASS_METHODS_Dog __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    sizeof(_objc_method),
    1,
    {{(struct objc_selector *)"classFun", "v16@0:8", (void *)_C_Dog_classFun}}
};
+ (Class)class {
    return self;
}

- (Class)class {
    return object_getClass(self);
}

BOOL class_isMetaClass(Class cls)
{
    if (!cls) return NO;
    return cls->isMetaClass();
}
 bool isMetaClass() {
        return info & CLS_META;
 }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末皆撩,一起剝皮案震驚了整個濱河市扣墩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌扛吞,老刑警劉巖呻惕,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異滥比,居然都是意外死亡亚脆,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門守呜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來型酥,“玉大人山憨,你說我怎么就攤上這事∶趾恚” “怎么了郁竟?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長由境。 經(jīng)常有香客問我棚亩,道長,這世上最難降的妖魔是什么虏杰? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任讥蟆,我火速辦了婚禮,結(jié)果婚禮上纺阔,老公的妹妹穿的比我還像新娘瘸彤。我一直安慰自己,他們只是感情好笛钝,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布质况。 她就那樣靜靜地躺著,像睡著了一般玻靡。 火紅的嫁衣襯著肌膚如雪结榄。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天囤捻,我揣著相機與錄音臼朗,去河邊找鬼。 笑死蝎土,一個胖子當著我的面吹牛视哑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播瘟则,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼黎炉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了醋拧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤淀弹,失蹤者是張志新(化名)和其女友劉穎丹壕,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體薇溃,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡菌赖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了沐序。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片琉用。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡堕绩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出邑时,到底是詐尸還是另有隱情奴紧,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布晶丘,位于F島的核電站黍氮,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏浅浮。R本人自食惡果不足惜沫浆,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望滚秩。 院中可真熱鬧专执,春花似錦、人聲如沸郁油。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽已艰。三九已至痊末,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間哩掺,已是汗流浹背凿叠。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留嚼吞,地道東北人盒件。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像舱禽,于是被迫代替她去往敵國和親炒刁。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354

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

  • 原文出處:南峰子的技術(shù)博客 Objective-C語言是一門動態(tài)語言誊稚,它將很多靜態(tài)語言在編譯和鏈接時期做的事放到了...
    _燴面_閱讀 1,229評論 1 5
  • 本文轉(zhuǎn)載自:http://southpeak.github.io/2014/10/25/objective-c-r...
    idiot_lin閱讀 935評論 0 4
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉翔始,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,709評論 0 9
  • Objective-C語言是一門動態(tài)語言,它將很多靜態(tài)語言在編譯和鏈接時期做的事放到了運行時來處理里伯。這種動態(tài)語言的...
    有一種再見叫青春閱讀 585評論 0 3
  • Objective-C語言是一門動態(tài)語言城瞎,他將很多靜態(tài)語言在編譯和鏈接時期做的事情放到了運行時來處理。這種動態(tài)語言...
    tigger丨閱讀 1,398評論 0 8