iOS消息發(fā)送機(jī)制

在<objc/objc.h>頭文件中查看class與object在Objective-C的定義

/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;     //類供璧,結(jié)構(gòu)體指針半抱,實(shí)際也是對象

/// Represents an instance of a class.
struct objc_object {    //實(shí)例對象的isa指針指向類對象泥耀,而類對象的isa指向元類
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;    //對象腾仅,結(jié)構(gòu)體指針

由上面可以看出,對象本質(zhì)是個(gè)結(jié)構(gòu)體指針碗誉,而類實(shí)際也是一個(gè)結(jié)構(gòu)體指針召嘶,所以類也是對象,實(shí)例對象的isa指針指向類(對象)哮缺,而類對象的isa指針指向元類
在objc/runtime.h中objc_class結(jié)構(gòu)體的定義如下:
以下為類結(jié)構(gòu)體弄跌,其中包含緩存方法列表、方法列表蝴蜓、屬性列表碟绑、父類指針等

struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;     //isa指針

#if !__OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;  // 父類
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;  // 類名
    long version                                             OBJC2_UNAVAILABLE; // 類的版本信息,默認(rèn)為0
    long info                                                OBJC2_UNAVAILABLE; // 類信息茎匠,供運(yùn)行期使用的一些位標(biāo)識
    long instance_size                                       OBJC2_UNAVAILABLE;  // 該類的實(shí)例變量大小
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;  // 該類的成員變量鏈表
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;   // 方法定義的鏈表
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;   // 緩存方法列表
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;  // 協(xié)議列表
#endif
} OBJC2_UNAVAILABLE;

消息發(fā)送流程:
1.首先檢查這個(gè)selector是不是要忽略格仲,如有了垃圾回收裝置就不會理會retain,release等
2.檢測這個(gè)selector的target是不是nil诵冒,OC允許我們對一個(gè)nil對象執(zhí)行任何方法不會Crash凯肋,因?yàn)檫\(yùn)行時(shí)會被忽略掉
3.查找這個(gè)類的實(shí)現(xiàn)IMP,先從緩存方法列表cache里查找汽馋,執(zhí)行過的方法會添加到該列表中侮东,如果找到了就運(yùn)行對應(yīng)的函數(shù)去執(zhí)行相應(yīng)的代碼
4.如果沒有找到就找類的方法列表methodLists中是否有對應(yīng)的方法,找到則執(zhí)行
5.如果該對象的類的方法列表中找不到就到父類的方法列表中查找豹芯,一直找到NSObject類為止
6.如果還是沒找到就要開始進(jìn)入消息轉(zhuǎn)發(fā)(動態(tài)方法解析悄雅,備援接收者,消息重定向)
*動態(tài)方法解析
當(dāng)runtime系統(tǒng)在Cache和類的方法列表(包括父類)中找不到要執(zhí)行的方法時(shí)runtime會調(diào)用resolveInstanceMethod: 或者resolveClassMethod: 來給我們一次動態(tài)添加方法實(shí)現(xiàn)的機(jī)會铁蹈,在該方法中可以使用class_addMethod動態(tài)添加方法宽闲,則例如:

//動態(tài)添加一個(gè)方法
+ (BOOL)resolveInstanceMethod:(SEL)sel{
    NSString * methodName = NSStringFromSelector(sel);
    if([methodName isEqualToString:@"sendMessage:"]){
        class_addMethod([self class], @selector(sendMessage:), (IMP)sendMessage, "v@:@");
       return YES;
    }
    return [super resolveInstanceMethod:name];  
}
void sendMessage(id self,SEL cmd,id value){
    NSLog(@"value=%@",value);
}

動態(tài)方法解析是在消息轉(zhuǎn)發(fā)機(jī)制侵入之前執(zhí)行,動態(tài)方法解析器將會首先給予提供該方法選擇器對應(yīng)的IMP的機(jī)會握牧。如果你想讓該方法選擇器被傳送到轉(zhuǎn)發(fā)機(jī)制容诬,就讓resolveInstanceMethod:方法返回NO。
*備援接收者
當(dāng)對象所屬類不能動態(tài)添加方法后沿腰,runtime就會詢問當(dāng)前的接受者是否有其他對象可以處理這個(gè)未知的selector

- (id)forwardingTargetForSelector:(SEL)aSelector{
    NSString * methodName = NSStringFromSelector(aSelector);
    if([methodName isEqualToString:@"sendMessage:"]){
        return [[OtherObject alloc]init];//返回一個(gè)實(shí)現(xiàn)了某方法的對象览徒,讓他去調(diào)用,例如:OtherObject對象
    }
    return [super forwardingTargetForSelector:aSelector];
}

*消息重定向
當(dāng)沒有備援接收者時(shí)颂龙,就只剩下最后一次機(jī)會习蓬,那就是消息重定向。這個(gè)時(shí)候runtime會將未知消息的所有細(xì)節(jié)都封裝為NSInvocation對象

//消息中轉(zhuǎn),丟給能接受這個(gè)消息處理的對象
//獲取方法簽名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
    NSString * methodName = NSStringFromSelector(aSelector);
    if([methodName isEqualToString:@"sendMessage:"]){
        return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
    }
    return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
    SEL sel = anInvocation.selector;
    OtherObject * oth = [[OtherObject alloc]init];
    if([oth respondsToSelector:sel]){
        [anInvocation invokeWithTarget:oth];
    }else{
        return [super forwardInvocation:anInvocation];
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末厘托,一起剝皮案震驚了整個(gè)濱河市友雳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌铅匹,老刑警劉巖押赊,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡流礁,警方通過查閱死者的電腦和手機(jī)涕俗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來神帅,“玉大人再姑,你說我怎么就攤上這事≌矣” “怎么了元镀?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長霎桅。 經(jīng)常有香客問我栖疑,道長,這世上最難降的妖魔是什么滔驶? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任遇革,我火速辦了婚禮,結(jié)果婚禮上揭糕,老公的妹妹穿的比我還像新娘萝快。我一直安慰自己,他們只是感情好著角,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布揪漩。 她就那樣靜靜地躺著,像睡著了一般吏口。 火紅的嫁衣襯著肌膚如雪氢拥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天锨侯,我揣著相機(jī)與錄音,去河邊找鬼冬殃。 笑死囚痴,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的审葬。 我是一名探鬼主播深滚,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼涣觉!你這毒婦竟也來了痴荐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤官册,失蹤者是張志新(化名)和其女友劉穎生兆,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體膝宁,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鸦难,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年根吁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片合蔽。...
    茶點(diǎn)故事閱讀 40,488評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡击敌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拴事,到底是詐尸還是另有隱情沃斤,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布刃宵,位于F島的核電站衡瓶,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏组去。R本人自食惡果不足惜鞍陨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望从隆。 院中可真熱鬧诚撵,春花似錦、人聲如沸键闺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽辛燥。三九已至筛武,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間挎塌,已是汗流浹背徘六。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留榴都,地道東北人待锈。 一個(gè)月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像嘴高,于是被迫代替她去往敵國和親竿音。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評論 2 359

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

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉拴驮,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,725評論 0 9
  • 一春瞬、OC語言的特性 首先,想要了解iOS的消息發(fā)送機(jī)制套啤,我們需要先理解OC這門語言宽气。相較于靜態(tài)語言而言,動態(tài)語言是...
    學(xué)知無涯閱讀 786評論 0 9
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,111評論 1 32
  • 一:舉例說明 NSLog(@"[self class] = %@",[self class]); ...
    code_牧軒閱讀 544評論 0 0
  • 第44章 嫣島主的出現(xiàn),快樂島的人們似乎更快樂了抹竹,送完禮后他們又各自干有興趣的事去线罕。 “我們劃船比...
    本耳朵閱讀 588評論 0 3