建議先看下
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的指令季春,可以將具體的類型表示成字符串編碼。
- @encode實(shí)際上是編譯器指令其中的一種消返。
- @encode能夠返回一個(gè)Objective-C 類型編碼(Objective-C Type Encodings)载弄。
- @encode是一種編譯器內(nèi)部表示的字符串耘拇,方便識(shí)別,類似于 ANSI C 的 typeof 操作宇攻。
在Objective-C中惫叛,用@encode指令的方式來表示,可以方便Runtime內(nèi)部利用類型編碼幫助加快消息分發(fā)逞刷。
當(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;
}
那么以這個(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方法讀取
例如讀取下{{"name","T@\"NSString\",C,N,V_name"},
-
T
: type -
@
: 變量類型 -
C
: copy -
N
: nonatomic -
V
: variable 變量,即下劃線變量 _Name