Runtime(一)

isa

  • arm64 之前,isa就是一個普通的指針,它指向classormeta-class
  • arm64之后,對isa進行了優(yōu)化,變成了一個共同體(union)結構,還使用位域來存儲更多信息.
    先來看一個例子:新建person
@interface Person : NSObject

- (void)setTall:(BOOL)tall;
- (void)setRich:(BOOL)rich;
- (void)setHandSome:(BOOL)handSome;

- (BOOL)getTall;
- (BOOL)getRich;
- (BOOL)getHandSome;

@end

再來.m文件

//掩碼 進行位運算
//#define ISTallMASK  1
//#define ISRichMASK  2
//#define ISHandSomeMASK  4

#define ISTallMASK  (1<<0)
#define ISRichMASK  (1<<1)
#define ISHandSomeMASK  (1<<2)

@interface Person()
{
    char _tallRichHandsome;
}

@end

@implementation Person

- (instancetype)init
{
    self = [super init];
    if (self) {
        //從右至左tall rich handsome
        _tallRichHandsome = 0b00000000;
    }
    return self;
}

- (void)setTall:(BOOL)tall{
    if (tall) {
        // | 或運算 有1則為1
        /*
            0000 0001
            0000 0001
         */
        _tallRichHandsome = _tallRichHandsome | ISTallMASK;
    }else{
        /*
            0000 0101
            1111 1110
            先取反 在進行&運算 保證其他為不變 標志位必為0
         */
        _tallRichHandsome = _tallRichHandsome & ~ISTallMASK;
    }
}

- (void)setRich:(BOOL)rich{
    if (rich) {
        _tallRichHandsome = _tallRichHandsome | ISRichMASK;
    }else{
        _tallRichHandsome = _tallRichHandsome & ~ISRichMASK;
    }
}

- (void)setHandSome:(BOOL)handSome{
    if (handSome) {
        _tallRichHandsome = _tallRichHandsome | ISHandSomeMASK;
    }else{
        _tallRichHandsome = _tallRichHandsome & ~ISHandSomeMASK;
    }
}

- (BOOL)getTall{
    //&運算  同為1則為1
    /*
     0000 0000
     0000 0001  // 十進制1*2^0 = 1
     */
    return !!(_tallRichHandsome & ISTallMASK);
}

- (BOOL)getRich{
    /*
        0000 0000
        0000 0010  // 十進制1*2^1 = 2
     */
    return !!(_tallRichHandsome & ISRichMASK);
}

- (BOOL)getHandSome{
    /*
     0000 0000
     0000 0100  // 十進制1*2^2 = 4
     */
    return !!(_tallRichHandsome & ISHandSomeMASK);
}

這樣我們就實現(xiàn)了一個字節(jié)存儲3個BOOL變量.如果以后要增加到4個BOOL變量,不免有些麻煩,接下來優(yōu)化一下.

@interface Person()
{
//    char _tallRichHandsome;
    //位域
    struct {
        char tall :1;//表示只占一位
        char rich :1;
        char handsome :1;
        
    }_tallRichHandsome;
}

@implementation Person

- (void)setTall:(BOOL)tall{
    _tallRichHandsome.tall = tall;
}

- (void)setRich:(BOOL)rich{
  _tallRichHandsome.rich = rich;
}

- (void)setHandSome:(BOOL)handSome{
    _tallRichHandsome.handsome = handSome;
}

- (BOOL)getTall{
//    BOOL isRet = _tallRichHandsome.tall
    //這里強制轉換 一個BOOL 類型是占一個字節(jié) tall這里是0x01 強轉后變 1111 1111 = 255,所以這里需要2次取反拿到正確的值.
    return !!(_tallRichHandsome.tall);
}

- (BOOL)getRich{
    return !!(_tallRichHandsome.rich);
}

- (BOOL)getHandSome{
   return !!(_tallRichHandsome.handsome);

@end
        Person *persn = [[Person alloc]init];
        [persn setTall:YES];
        [persn setRich:NO];
        [persn setHandSome:NO];
        NSLog(@"%d-- %d ---%d",persn.getRich,persn.getTall,persn.getHandSome);
        
(lldb) p/x &(persn->_tallRichHandsome)
((anonymous struct) *) $0 = 0x000000010281f2a8
(lldb) x 0x000000010281f2a8
0x10281f2a8: 01 00 00 00 00 00 00 00 63 46 1b 41 ff 7f 00 00  ........cF.A....
0x10281f2b8: 4a 97 fb 42 ff 7f 00 00 b9 be 52 45 ff 7f 00 00  J..B......RE....

01 00 00 00 00 00 00 00 第2個十六進制位,轉換成二進制是0000 0001說明tall被放在最右邊.
接下來看看蘋果的做法

@interface Person()
{
//    位域
    union{

        char bits;
        struct {
            char tall :1;
            char rich :1;
            char handsome :1;
            
        };
        
    }_tallRichHandsome;
}

@end

union是一個共同體,bits占一個字節(jié),struct也占一個字節(jié).
.m文件


- (void)setTall:(BOOL)tall{
    if (tall) {
        _tallRichHandsome.bits = _tallRichHandsome.bits | ISTallMASK;
    }else{
        _tallRichHandsome.bits = _tallRichHandsome.bits & ~ISTallMASK;
    }
}

再來看isa的結構

union isa_t 
{

    Class cls;
    uintptr_t bits;
#   define ISA_MASK        0x0000000ffffffff8ULL
#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL
    struct {
        uintptr_t nonpointer        : 1;
        uintptr_t has_assoc         : 1;
        uintptr_t has_cxx_dtor      : 1;
        uintptr_t shiftcls          : 33; // MACH_VM_MAX_ADDRESS 0x1000000000
        uintptr_t magic             : 6;
        uintptr_t weakly_referenced : 1;
        uintptr_t deallocating      : 1;
        uintptr_t has_sidetable_rc  : 1;
        uintptr_t extra_rc          : 19;
    };
}
  • nonpointer
    0忧便,代表普通的指針,存儲著Class帽借、Meta-Class對象的內存地址
    1茬腿,代表優(yōu)化過,使用位域存儲更多的信息
  • has_assoc
    是否有設置過關聯(lián)對象宜雀,如果沒有切平,釋放時會更快
  • has_cxx_dtor
    是否有C++的析構函數(shù)(.cxx_destruct),如果沒有辐董,釋放時會更快
  • shiftcls
    存儲著Class悴品、Meta-Class對象的內存地址信息
  • magic
    用于在調試時分辨對象是否未完成初始化
  • weakly_referenced
    是否有被弱引用指向過,如果沒有简烘,釋放時會更快
  • deallocating
    對象是否正在釋放
  • extra_rc
    里面存儲的值是引用計數(shù)器減1
  • has_sidetable_rc
    引用計數(shù)器是否過大無法存儲在isa中
    如果為1苔严,那么引用計數(shù)會存儲在一個叫SideTable的類的屬性中

Class結構

struct objc_class  {
    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
}

bits & FAST_DATA_MASK 得到


//類的初始信息
struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
#ifdef __LP64__
    uint32_t reserved;
#endif

    const uint8_t * ivarLayout;
    
    const char * name;
    method_list_t * baseMethodList;
    protocol_list_t * baseProtocols;
    const ivar_list_t * ivars;

    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;

    method_list_t *baseMethods() const {
        return baseMethodList;
    }
};

struct class_rw_t {
    // Be warned that Symbolication knows the layout of this structure.
    uint32_t flags;
    uint32_t version;

    const class_ro_t *ro;

    method_array_t methods;//方法列表
    property_array_t properties;//屬性列表
    protocol_array_t protocols;//協(xié)議列表

    Class firstSubclass;
    Class nextSiblingClass;

    char *demangledName;
{

method_array_t是一個二維數(shù)組里面最終存放的是method_t

struct method_t {
    SEL name;
    const char *types;
    IMP imp;
}
  • name; 函數(shù)名
  • types; 編碼(函數(shù)返回值類型,參數(shù)類型)
  • imp; 函數(shù)地址(指向函數(shù)的指針)

SEL代表方法\函數(shù)名,一般叫做選擇器孤澎,底層結構跟char *類似
可以通過@selector()sel_registerName()獲得
可以通過sel_getName()NSStringFromSelector()轉成字符串
不同類中相同名字的方法届氢,所對應的方法選擇器是相同的

iOS中提供了一個叫做@encode的指令,可以將具體的類型表示成字符串編碼


image.png
image.png

接下來看看cache_t結構

struct bucket_t {
    cache_key_t _key;// SEL作為key
    IMP _imp;//函數(shù)的內存地址
};

struct cache_t {
    struct bucket_t *_buckets;//哈希表
    mask_t _mask;//哈希表長度 - 1
    mask_t _occupied;//已經(jīng)緩存的方法數(shù)量
}

哈希表相關資料鏈接

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末覆旭,一起剝皮案震驚了整個濱河市退子,隨后出現(xiàn)的幾起案子岖妄,更是在濱河造成了極大的恐慌,老刑警劉巖寂祥,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件荐虐,死亡現(xiàn)場離奇詭異,居然都是意外死亡丸凭,警方通過查閱死者的電腦和手機福扬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惜犀,“玉大人铛碑,你說我怎么就攤上這事∷浣纾” “怎么了汽烦?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長浓恳。 經(jīng)常有香客問我,道長碗暗,這世上最難降的妖魔是什么颈将? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮言疗,結果婚禮上晴圾,老公的妹妹穿的比我還像新娘。我一直安慰自己噪奄,他們只是感情好死姚,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著勤篮,像睡著了一般都毒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上碰缔,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天账劲,我揣著相機與錄音,去河邊找鬼金抡。 笑死瀑焦,一個胖子當著我的面吹牛,可吹牛的內容都是我干的梗肝。 我是一名探鬼主播榛瓮,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼巫击!你這毒婦竟也來了禀晓?” 一聲冷哼從身側響起精续,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎匆绣,沒想到半個月后驻右,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡崎淳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年堪夭,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拣凹。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡森爽,死狀恐怖,靈堂內的尸體忽然破棺而出嚣镜,到底是詐尸還是另有隱情爬迟,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布菊匿,位于F島的核電站付呕,受9級特大地震影響,放射性物質發(fā)生泄漏跌捆。R本人自食惡果不足惜徽职,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望佩厚。 院中可真熱鬧姆钉,春花似錦、人聲如沸抄瓦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽钙姊。三九已至毯辅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間煞额,已是汗流浹背悉罕。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留立镶,地道東北人壁袄。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像媚媒,于是被迫代替她去往敵國和親嗜逻。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內容