IOS底層(十): 類相關(guān): 成員變量與屬性

OC底層源碼/原理合集

建議先看下
IOS底層(九): 類相關(guān): 類結(jié)構(gòu)分析
IOS底層(八): alloc相關(guān): isa與類關(guān)聯(lián)源碼分析

@interface ViewController (){
    
    NSString *name ; // 成員變量, 實(shí)例變量
    int age;   // 成員變量, 基本數(shù)據(jù)類型變量
    id data;   // 成員變量, 實(shí)例變量
}

@property (nonatomic, strong) NSString *hobby;  //屬性

@end

成員變量

  • 通常在.h/.m文件@interface以{ } 形式定義的變量
成員變量的訪問權(quán)限
@interface ViewController (){
    
    NSString * A; 
    
@public
    NSString * B;
    
@protected
    NSString * C;
    
@private
    NSString * D;
    
    @package
    NSString * E;
}
  • @public:在任何地方都能直接訪問對(duì)象的成員變量

  • @private:只能在當(dāng)前類的對(duì)象方法中直接訪問, 如果子類要訪問需要調(diào)用父類的get/set方法

  • @protected:可以在當(dāng)前類及其子類對(duì)象方法中直接訪問,變量默認(rèn)的訪問權(quán)限就是 protected

  • @package:只能在framework內(nèi)部的類是@protected的權(quán)限仿滔,對(duì)于外部的類是@private疚察,相當(dāng)于框架級(jí)的保護(hù)權(quán)限伦乔,適合使用在靜態(tài)庫.a中君编。

實(shí)例變量

  • 如果成員變量是一個(gè)(類的實(shí)例化), 則這個(gè)變量為實(shí)例變量, 例如上面例子name, data (id 是 OC特有的類型悦污。從本質(zhì)上講蒙秒, id 等同于 (void *))都是實(shí)例變量, 而age是int型, 是基礎(chǔ)數(shù)據(jù)類型變量
  • 實(shí)例變量 + 基礎(chǔ)數(shù)據(jù)類型變量 = 成員變量

屬性 (屬性變量)

  • 一般用 @property表示

  • 編譯器會(huì)自動(dòng)為屬性生成set, get方法, 以及生成成員變量_documentsDirectory(即成員變量名前加下劃線)

  • 成員屬性包含了成員變量

  • 可以通過點(diǎn)語法訪問屬性桑李,編譯器會(huì)把點(diǎn)語法轉(zhuǎn)換為對(duì)存取方法的調(diào)用 (使用“點(diǎn)語法”的效果與直接調(diào)用存取方法相同)。self.調(diào)用奠支,即self.documentsDirectory,如果想用self->調(diào)用成員屬性就只能self->_documentsDirectory, 這樣調(diào)用太麻煩, 一般會(huì)再用@synthesize對(duì)帶底杠的成員屬性名重新定名

@synthesize fileName, documentsDirectory

這樣就可以直接訪問成員屬性名self->documentsDirectory

  • 屬性是用于與其他對(duì)象交互的變量, 正因?yàn)橐c其他對(duì)象交互, 就有了屬性修飾符或者叫屬性特質(zhì), 如:nonatomic, readwrite, copy 等等

屬性/成員變量本質(zhì) (底層)

首先建立一個(gè)main項(xiàng)目, 添加些成員變量, 屬性如圖(創(chuàng)建只有main.m項(xiàng)目)

屬性成員變量例子

clang一下生成cpp文件

clang -rewrite-objc main.m -o main.cpp

建議先看下
IOS底層(八): alloc相關(guān): isa與類關(guān)聯(lián)源碼分析 前面的Clang那里

通過我們通過TestObj查找 (因?yàn)閷傩?成員變量都是TestObj的), 來到這里

屬性成員變量底層

① 首先可看到TestObj 來自于 NSObject的繼承,
屬性在底層會(huì)被編譯成成員變量, 區(qū)別是帶下劃線 _
屬性在底層會(huì)自動(dòng)生成set, get方法, 而成員變量不會(huì)有

④ 同時(shí)還有我們之前得到的結(jié)論

  • 通過@interface XXXX {}定義的成員變量抚芦,會(huì)存儲(chǔ)在類的bits屬性中倍谜,通過bits --> data() -->ro() --> ivars獲取成員變量列表,除了包括成員變量叉抡,還包括屬性的成員變量

  • 通過@property定義的屬性尔崔,也會(huì)存儲(chǔ)在bits屬性中,通過bits --> data() --> properties() --> list獲取屬性列表褥民,其中只包含property屬性


接下來往后看

屬性成員變量底層

可看到每一個(gè)方法都有一個(gè)sel, imp

  • sel : 方法編號(hào), 可以理解成一本書的目錄, 可通過對(duì)應(yīng)名稱找到頁碼

  • imp : 函數(shù)指針地址, 可以理解成書的頁碼, 方便找到具體實(shí)現(xiàn)的函數(shù)

  • T, @, v在底層是一些簽名, Type Encodings里面有詳細(xì)介紹

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

  1. @encode實(shí)際上是編譯器指令其中的一種消返。
  2. @encode能夠返回一個(gè)Objective-C 類型編碼(Objective-C Type Encodings)载弄。
  3. @encode是一種編譯器內(nèi)部表示的字符串耘拇,方便識(shí)別,類似于 ANSI C 的 typeof 操作宇攻。

在Objective-C中惫叛,用@encode指令的方式來表示,可以方便Runtime內(nèi)部利用類型編碼幫助加快消息分發(fā)逞刷。

Type Encodings 蘋果官方

Property Type String 蘋果官方

Type Encodings

當(dāng)然我們也可以自己嘗試打印一下

#pragma mark - 各種類型編碼
void lgTypes(){
    NSLog(@"char --> %s",@encode(char));
    NSLog(@"int --> %s",@encode(int));
    NSLog(@"short --> %s",@encode(short));
    NSLog(@"long --> %s",@encode(long));
    NSLog(@"long long --> %s",@encode(long long));
    NSLog(@"unsigned char --> %s",@encode(unsigned char));
    NSLog(@"unsigned int --> %s",@encode(unsigned int));
    NSLog(@"unsigned short --> %s",@encode(unsigned short));
    NSLog(@"unsigned long --> %s",@encode(unsigned long long));
    NSLog(@"float --> %s",@encode(float));
    NSLog(@"bool --> %s",@encode(bool));
    NSLog(@"void --> %s",@encode(void));
    NSLog(@"char * --> %s",@encode(char *));
    NSLog(@"id --> %s",@encode(id));
    NSLog(@"Class --> %s",@encode(Class));
    NSLog(@"SEL --> %s",@encode(SEL));
    int array[] = {1,2,3};
    NSLog(@"int[] --> %s",@encode(typeof(array)));
    typedef struct person{
        char *name;
        int age;
    }Person;
    NSLog(@"struct --> %s",@encode(Person));
    
    typedef union union_type{
        char *name;
        int a;
    }Union;
    NSLog(@"union --> %s",@encode(Union));

    int a = 2;
    int *b = {&a};
    NSLog(@"int[] --> %s",@encode(typeof(b)));
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        lgTypes();
        NSLog(@"Hello, World!");
    }
    return 0;
}

image.png

那么以這個(gè)為例子, 我們讀一下"@16@0:8"

{(struct objc_selector *)"nickname", "@16@0:8", (void *)_I_TestObj_nickname}

static NSString * _I_TestObj_nickname(TestObj * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_TestObj$_nickname)); }
  • @: 為返回值
  • 16: 為總共占用字節(jié)16字節(jié)
  • @: 為第一個(gè)參數(shù) id統(tǒng)配類型占8字節(jié)(系統(tǒng)自動(dòng)生成的typedef struct objc_object *id)
  • 0: 從0開始
  • 冒號(hào): : sel, 占8字節(jié)(系統(tǒng)自動(dòng)生成的sel _cmd)
  • 8: 從位置8開始

clang編譯輸出了屬性的attribute 嘉涌,同樣也可以通過property_getAttributes方法讀取

property type string
attribute

例如讀取下{{"name","T@\"NSString\",C,N,V_name"},

  • T: type
  • @: 變量類型
  • C: copy
  • N: nonatomic
  • V: variable 變量,即下劃線變量 _Name
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末夸浅,一起剝皮案震驚了整個(gè)濱河市仑最,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌帆喇,老刑警劉巖警医,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異番枚,居然都是意外死亡法严,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門葫笼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來深啤,“玉大人,你說我怎么就攤上這事路星∷萁郑” “怎么了?”我有些...
    開封第一講書人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵洋丐,是天一觀的道長呈昔。 經(jīng)常有香客問我,道長友绝,這世上最難降的妖魔是什么堤尾? 我笑而不...
    開封第一講書人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮迁客,結(jié)果婚禮上郭宝,老公的妹妹穿的比我還像新娘。我一直安慰自己掷漱,他們只是感情好粘室,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著卜范,像睡著了一般衔统。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評(píng)論 1 304
  • 那天锦爵,我揣著相機(jī)與錄音舱殿,去河邊找鬼。 笑死棉浸,一個(gè)胖子當(dāng)著我的面吹牛怀薛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播迷郑,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼枝恋,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了嗡害?” 一聲冷哼從身側(cè)響起焚碌,我...
    開封第一講書人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎霸妹,沒想到半個(gè)月后十电,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡叹螟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年鹃骂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片罢绽。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡畏线,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出良价,到底是詐尸還是另有隱情寝殴,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布明垢,位于F島的核電站蚣常,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏痊银。R本人自食惡果不足惜抵蚊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望溯革。 院中可真熱鬧泌射,春花似錦、人聲如沸鬓照。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽豺裆。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間臭猜,已是汗流浹背躺酒。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蔑歌,地道東北人羹应。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像次屠,于是被迫代替她去往敵國和親园匹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

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