Objective-C中的方法默認被隱藏了兩個參數:self和_cmd。self指向對象本身,_cmd指向方法本身。舉兩個例子來說明:
例一:- (NSString *)name
這個方法實際上有兩個參數:self和_cmd。
例二:- (void)setValue:(int)val
這個方法實際上有三個參數:self, _cmd和val。
被指定爲動態實現的方法的參數類型有如下的要求:
A.第一個參數類型必須是id(就是self的類型)
B.第二個參數類型必須是SEL(就是_cmd的類型)
C.從第三個參數起,可以按照原方法的參數類型定義。舉兩個例子來說明:
例一:setHeight:(CGFloat)height中的參數height是浮點型的,所以第三個參數類型就是f。
例二:再比如setName:(NSString *)name中的參數name是字符串類型的,所以第三個參數類型就是@
這裏v@:@是什麼東西呢?實際上,這裏的第一個字符v代表函數的返回類型是void,後面三個字符參考上面2)中的解釋就可以知道,分別是self, _cmd, name這三個參數的類型id, SEL, NSString。
接着程序進入forwardInvocation方法。得到的key爲方法名稱setName:,然後利用[invocation getArgument:&obj atIndex:2]; 獲取到參數值,這裏是“c++ primer”。這裏的index爲什麼要取2呢?如前面分析,第0個參數是self,第1個參數是_cmd,第2個參數纔是方法後面帶的那個參數。
最後利用一個可變字典來賦值。這樣就完成了整個setter過程。
4)在main.m中有一句代碼是 NSLog(@"%@", book.name);,程序運行到這裏時,會去Book.m中尋找name這個取值方法 。但是Book.m裏並沒有這個取值方法,於是程序進入methodSignatureForSelector:中進行消息轉發。執行完之後,以"@@:"作爲方法簽名類型返回。這裏第一字符@代表函數返回類型NSString,第二個字符@代表self的類型id,第三個字符:代表_cmd的類型SEL。
接着程序進入forwardInvocation方法。得到的key爲方法名稱name。最後根據這個key從字典裏獲取相應的值,這樣就完成了整個getter過程。