iOS底層-self被芳、super缰贝、superclass

基本理解:

  • self : 當(dāng)前方法的調(diào)用者
  • super:不是一個(gè)指針,編譯指示器(標(biāo)識(shí)符),在程序編譯時(shí)內(nèi)部會(huì)做一些特殊處理 (底層會(huì)被編譯成 objc_msgSendSuper()方法)
  • superclass:是一個(gè)方法畔濒,返回的結(jié)果是調(diào)用者的父類對(duì)象

super 的作用只是告訴編譯器剩晴,查找方法的時(shí)候不用找自己的方法列表,直接從父類開始找侵状。(調(diào)用者還是我自己)
我們?cè)谘芯糠椒ú檎伊鞒痰臅r(shí)候知道赞弥,發(fā)送消息是先找自己的方法,然后遞歸找父類的方法趣兄, 而super就是告訴編譯器绽左,不要從我這找了,直接從父類開始找吧艇潭。

每當(dāng)講解self與super的時(shí)候拼窥,都會(huì)拿這個(gè)經(jīng)典的代碼示例來(lái)做說(shuō)明:

// 背景  Person:NSObject     Student:Person

//重寫Student的init方法
- (instancetype)init
{
    if (self = [super init]) {
        NSLog(@"self = %@",NSStringFromClass([self class]));
        NSLog(@"super = %@",NSStringFromClass([super class]));
    }
    return self;
}

//初始化Studen([Student new])  打印結(jié)果
self = Student
super = Student    
/**
?? 如果 定義一個(gè)Student子類 : StudentChild : Student
子類  StudentChild 不重寫 init方法  
執(zhí)行  [StudentChild  new];
那么這里打印的  是 

self = StudentChild
super = StudentChild    
*/

??:self 和 super 都是調(diào)用者
Sutdent 調(diào)用init 那么 self、super 就是Student
StudentChild 調(diào)用init 那么 self蹋凝、super 就是StudentChild

按照一般人的想法:這里的super 應(yīng)該是Person鲁纠,而實(shí)際上卻是Student,那是因?yàn)?在理解super之前容易將super 和 superclass混淆

從源碼來(lái)分析self鳍寂、super

上面有說(shuō)到:super 是 編譯指示器(標(biāo)識(shí)符) 而不是指針改含,self是方法調(diào)用者,是一個(gè)指針
?? 只要記住super 不是 superclass迄汛,理解super就很容易了

我們從匯編代碼來(lái)看看候味,他究竟干了什么

cd 到Student.m的上一級(jí)目錄,然后通過命令:

clang -rewrite-objc Student.m

// 或者  
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc Student.m -o out.cpp  (Student.m 是需要轉(zhuǎn)換的文件  out.cpp 是轉(zhuǎn)換之后的名字隔心,也可以省略,默認(rèn)原來(lái)的名字(從-o 開始省略))

可以找到這樣一段底層代碼


static instancetype _I_Student_init(Student * self, SEL _cmd) {
    if (self = ((Student *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("init"))) {
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_p8_l89z5sss5qx7r1082_jrxy_40000gp_T_Student_3430f4_mi_0,NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class"))));
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_p8_l89z5sss5qx7r1082_jrxy_40000gp_T_Student_3430f4_mi_1,NSStringFromClass(((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("class"))));
    }
    return self;
}

//簡(jiǎn)化之后
static instancetype _I_Student_init(Student * self, SEL _cmd) {
    if (self = ((Student *(*)objc_msgSendSuper)({(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("init"))) {
        NSLog(NSStringFromClass(objc_msgSend)((id)self, sel_registerName("class"))));
        NSLog(NSStringFromClass(objc_msgSendSuper)({(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("class"))));
    }
    return self;
}

從簡(jiǎn)化之后的代碼能看以下信息

  • 1尚胞、調(diào)用[self class]的時(shí)候硬霍,底層是調(diào)用的 objc_msgSend(....)
  • 2、調(diào)用[super class]的時(shí)候笼裳,底層調(diào)用的是 objc_msgSuperSend(....)
  • 3唯卖、super調(diào)用的方法粱玲,從父類開始查找[class_getSuperclass(...)]

知道了調(diào)用的方法之后,我們從底層源碼源碼頁(yè)面中搜索objc
來(lái)分析:

OBJC_EXPORT void
objc_msgSend(void /* id self, SEL op, ... */ )

OBJC_EXPORT void
objc_msgSendSuper(void /* struct objc_super *super, SEL op, ... */ )

struct objc_super {
    /// Specifies an instance of a class.
    __unsafe_unretained _Nonnull id receiver;
    __unsafe_unretained _Nonnull Class super_class;
};

objc_msgSend相對(duì)比較好理解拜轨,對(duì)應(yīng)到這里抽减,[self class] 就是 objc_msgSend(調(diào)用者(self),調(diào)用方法(@selecter(class))橄碾,....(其他參數(shù)))

[super class] 中 objc_msgSendSuper() 的參數(shù)是一個(gè)objc_super結(jié)構(gòu)體 結(jié)構(gòu)體的第一個(gè)參數(shù)和objc_msgSend一樣卵沉,也是receive(self),只是通過第二個(gè)參數(shù) super_class 知道法牲,方法從父類去找

可以理解為 objc_msgSendSuper(調(diào)用者(self)史汗,從哪開始找(super_class),調(diào)用方法(@selecter(class)),....(其他參數(shù)))

self 再探

上面說(shuō)了super的理解拒垃,接下來(lái)對(duì)self梳理一遍

// 背景  Person:NSObject     Student:Person

//Person 聲明并實(shí)現(xiàn) readBook方法
//Person.h
- (void)readBook;

//Person.m
- (void)readBook
{
    NSLog(@"person readBook  self = %@",NSStringFromClass([self class]));
}

//Student 重寫readBook
- (void)readBook
{
    [super readBook];
    NSLog(@"Student readbook");
}

//初始化Studen 并調(diào)用readBook
Student *s = [Student new];
 [s readBook];

//先思考答應(yīng)結(jié)果停撞,再看運(yùn)行結(jié)果

//打印結(jié)果
person readBook  self = Student
Student readbook

上面的代碼中,在Person中的[self class] 中的self 依然是Student悼瓮,因?yàn)樽铋_始就說(shuō)過戈毒,self是調(diào)用者,在這里 是student調(diào)用了 readBook横堡,所以埋市,即使[self class]在Person,依然是Student

superclass

  • superclass:是一個(gè)方法翅萤,返回的結(jié)果是調(diào)用者的父類對(duì)象(有類方法和示例方法)
    從源碼中看
+ (Class)superclass {
    return self->superclass;
}

- (Class)superclass {
    return [self class]->superclass;
}

掉用superclass就是獲取對(duì)象所在類的superclass 從對(duì)象本質(zhì)(結(jié)構(gòu)體)中看:

struct objc_class : objc_object {
    // Class ISA;
    Class superclass;        //  <-----??  就是它
    cache_t cache; 
    class_data_bits_t bits;

    class_rw_t *data() { 
        return bits.data();
    }
    void setData(class_rw_t *newData) {
        bits.setData(newData);
    }

.......
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末恐疲,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子套么,更是在濱河造成了極大的恐慌培己,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胚泌,死亡現(xiàn)場(chǎng)離奇詭異省咨,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)玷室,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門零蓉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)榕酒,“玉大人岳悟,你說(shuō)我怎么就攤上這事捧韵∠确耍” “怎么了肢础?”我有些...
    開封第一講書人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵嫉戚,是天一觀的道長(zhǎng)梅肤。 經(jīng)常有香客問我伴郁,道長(zhǎng),這世上最難降的妖魔是什么秸脱? 我笑而不...
    開封第一講書人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任落包,我火速辦了婚禮,結(jié)果婚禮上摊唇,老公的妹妹穿的比我還像新娘咐蝇。我一直安慰自己,他們只是感情好巷查,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開白布有序。 她就那樣靜靜地躺著,像睡著了一般吮便。 火紅的嫁衣襯著肌膚如雪笔呀。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,785評(píng)論 1 290
  • 那天髓需,我揣著相機(jī)與錄音许师,去河邊找鬼。 笑死僚匆,一個(gè)胖子當(dāng)著我的面吹牛微渠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播咧擂,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼逞盆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了松申?” 一聲冷哼從身側(cè)響起云芦,我...
    開封第一講書人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贸桶,沒想到半個(gè)月后舅逸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡皇筛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年琉历,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片水醋。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡旗笔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拄踪,到底是詐尸還是另有隱情蝇恶,我是刑警寧澤,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布惶桐,位于F島的核電站艘包,受9級(jí)特大地震影響的猛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜想虎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望叛拷。 院中可真熱鬧舌厨,春花似錦、人聲如沸忿薇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)署浩。三九已至揉燃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間筋栋,已是汗流浹背炊汤。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留弊攘,地道東北人抢腐。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像襟交,于是被迫代替她去往敵國(guó)和親迈倍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348

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