最近在複習iOS中的消息轉發機制,若是須要在動態方法解析這一階段對消息進行處理,通常須要調用class_addMethod方法給類動態地增長方法,例如:api
我當時敲代碼的時候發現本身對於class_addMethod這個方法的第四個參數const char *types不太清楚,後來搜了一下類型編碼,發現網上的文章主要是對於屬性的類型編碼進行了介紹,也沒有人對函數的類型編碼進行介紹,就去看了一下文檔瞭解了一下。再後來發現介紹消息轉發機制的那篇文章中對於這個參數的傳入是錯誤的,數組
圖中添加的方法是void functionForMethod1(idself, SEL _cmd),編碼
傳入的函數類型編碼是"@:",cdn
而正確的函數類型編碼應該是"v@:",對象
下面讓咱們來看看這個方法:blog
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types); 開發
這個方法主要接受四個參數文檔
Class cls 要添加方法的類get
SEL name 被添加方法的名字
IMP imp 添加的方法的實現
const char *types 描述方法參數類型的字符數組。
描述方法參數類型的字符數組的第一個字符是表明返回值的類型,後面的字符依次表明參數的類型,由於Objective-C中的函數會包含兩個隱式參數,也就是方法調用者和方法名,例如
+(void)method
實際應該是
void method(id self, SEL _cmd)
若是返回值爲空,那麼函數的類型編碼的第一個字符是v,若是不爲空,則爲返回值類型對應的編碼,詳細的能夠看下面的編碼對應表
由於第一個參數是方法調用者,它的類型確定是對象類型,因此類型編碼的第二個字符必定是@
由於第二個參數是方法名的類型,第三個字符必定是:
因此這個函數
void method(id self, SEL _cmd)
的類型編碼爲 "v@:"
那麼若是要添加的函數是一個set函數,類型編碼是怎麼樣的呢?
-(void)setA:(NSString *)a
同理,set方法實際的函數是這樣的:
void setA(id self, SEL _cmd, id a)
與上面無參數的方法相比,只是多了一個參數,
因此類型編碼爲"v@:@",代碼爲
class_addMethod(self, @selector(setA:), (IMP)setA,"v@:@");
最後發現本身仍是太年輕了。。。
蘋果仍是考慮到了開發者手動寫函數的類型編碼容易出錯的狀況,因此仍是提供了api來獲取函數的類型編碼(其實我想說。。。既然能提供api獲取函數的類型編碼,爲何不在class_addMethod的實現中去獲取函數的類型編碼,而須要外部傳入)
主要是有這麼一個函數
const char * _Nullablemethod_getTypeEncoding(Method _Nonnull m)
經過傳入類名和,獲函數名,獲取函數的類型編碼,例如這樣: