一 概述:
Objective-C(簡(jiǎn)稱OC)的Cocoa層的API中有大量的[receiver message]消息發(fā)送機(jī)制,初學(xué)時(shí)我們往往把理解為一個(gè)object調(diào)用了一個(gè)method,而往往忽視了"消息機(jī)制"這句話的深刻含義,[receiver message]獨(dú)特機(jī)制區(qū)別于其他主流語(yǔ)言.
二 原理:
消息發(fā)送機(jī)制是Runtime通過(guò)selector快速查找IMP的過(guò)程,有了IMP這個(gè)函數(shù)指針,就可以執(zhí)行對(duì)應(yīng)的方法實(shí)現(xiàn).
[receiver message]會(huì)被編譯器轉(zhuǎn)換成為:
// arg1 ,arg2... 表示消息含有的參數(shù)
objc_msgSend(receiver, selector, arg1, arg2, ...)
如果消息的接受者能夠找到對(duì)應(yīng)的selector,相當(dāng)于執(zhí)行了這個(gè)對(duì)象方法,否則消息要么被轉(zhuǎn)發(fā),要么臨時(shí)向接受者動(dòng)態(tài)添加這個(gè) selector 對(duì)應(yīng)的實(shí)現(xiàn)內(nèi)容,要么就干脆崩潰.
那么儡循,objc.msgSend又是怎么確定應(yīng)該調(diào)用哪個(gè)方法的呢软啼?它有一個(gè)動(dòng)態(tài)查找過(guò)程烛愧,具體如下:
①在相應(yīng)對(duì)象的緩存方法列表中( objc_class的cache )查找調(diào)用的方法
②如果沒找到工腋,則在相應(yīng)對(duì)象的方法列表中找調(diào)用方法
③如果還沒找到色难,就到父類指針指向的對(duì)象中執(zhí)行①和②兩步蝴簇。
// 給 stuModel對(duì)象發(fā)送一個(gè)messageSender消息 在.h中不聲明 objc_msgSend/messageSender也可以發(fā)送消息給stuModel xcode 會(huì)有警告
objc_msgSend(stuModel, @selector(messageSender
// 帶參數(shù)
objc_msgSend(stuModel, @selector(messageSender:),@"hello runtime");
IMP:定義為 typedef void (*IMP)(void /* id,SEL,... */);
本質(zhì)是個(gè)函數(shù)指針,由編譯器生成,當(dāng)發(fā)送一條消息之后,最終它會(huì)執(zhí)行方法,就是由該函數(shù)指針定的,而IMP這個(gè)函數(shù)指針就是指向了這個(gè)方法的實(shí)現(xiàn).IMP指針方法實(shí)現(xiàn)和SEL一一對(duì)應(yīng)的.
三 super
super是OC的保留字,不是隱式參數(shù),它只是個(gè)''編譯器指示器',主要是針對(duì)父類
id objc_msgSendSuper(struct objc_super *super,SEL op,...)
當(dāng)消息傳遞給父類的時(shí)候,調(diào)用objc_msgSendSuper
,objc_super
這個(gè)結(jié)構(gòu)體會(huì)存放當(dāng)前函數(shù)里的self
(隱式參數(shù))的super_class
,即[self superclass];msgSendSuper
從當(dāng)前對(duì)象的父類方法開始,沿著父類繼承鏈查找.最終執(zhí)行到[super respondsToSelector:@selector(superHasNotThisSelector) ]
; 而respondsToSelector
這個(gè)方法是NSObject方法,而NSObjcet類位于所有類繼承的頂端,執(zhí)行這個(gè)方法會(huì)找到對(duì)應(yīng)的實(shí)現(xiàn)函數(shù)!
四 self
self
是OC的隱式參數(shù),之所以叫隱式參數(shù)是因?yàn)樵创a方法定義中并沒有聲明這個(gè)參數(shù),但我們可以引用它;self
本身也是個(gè)指針,在每個(gè)方法中都有一個(gè)self
指針,在函數(shù)中無(wú)法使用,可以使用self -> 成員變量
五 動(dòng)態(tài)方法
前面提到某些情況下消息的接受者無(wú)法找到對(duì)應(yīng)的selector
時(shí),會(huì)臨時(shí)向接受者動(dòng)態(tài)添加這個(gè)selector
對(duì)應(yīng)的實(shí)現(xiàn)內(nèi)容.
給某個(gè)屬性聲明@dynamic類型,編譯器會(huì)認(rèn)為這個(gè)屬性相關(guān)的方法會(huì)動(dòng)態(tài)提供,也就是說(shuō)編譯器不會(huì)默認(rèn)生成屬性的set
和get
方法了,而需要我們動(dòng)態(tài)提供,可以通過(guò)重載resolveInstanceMethod:
和resolveClassMethod
添加動(dòng)態(tài)方法.
代碼示例如下:
#import <Foundation/Foundation.h>
@interface AutoMehtodModel : NSObject
@property(nonatomic,copy)NSString *addAutoMethod;
@end
#import "AutoMehtodModel.h"
#import <objc/runtime.h>
@implementation AutoMehtodModel
@dynamic addAutoMethod;
/**
為addAutoMethod動(dòng)態(tài)添加set和get方法
**/
+(BOOL)resolveInstanceMethod:(SEL)sel
{
NSString *addSelectorStr = NSStringFromSelector(sel);
//v@:@是一種符合 涉及到https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
if ([addSelectorStr isEqualToString:@"setAddAutoMethod:"]) {
class_addMethod(self, sel, (IMP)autoSetter, "v@:@");
}else if ([addSelectorStr isEqualToString:@"addAutoMethod"]){
class_addMethod(self, sel, (IMP)autoGet, "@@:");
}
return [super resolveInstanceMethod:sel];
}
void autoSetter(id self,SEL _cmd, id value){
NSLog(@"set方法 === %@",value);
}
id autoGet(id self,SEL _cmd){
return @"get方法";
}
AutoMehtodModel *model = [[AutoMehtodModel alloc]init];
model.addAutoMethod = @"動(dòng)態(tài)方法";
NSLog(@"%@",model.addAutoMethod);
運(yùn)行結(jié)果:
2018-03-27 10:53:07.875514+0800 OC_Categroy[962:61285] set方法 === 動(dòng)態(tài)方法
2018-03-27 10:53:23.157687+0800 OC_Categroy[962:61285] get方法
參考文獻(xiàn):http://yulingtianxia.com/blog/2014/11/05/objective-c-runtime/