iOS開發之-NSInvocation

簡介

Objective-C 是動態語言,所有的消息都是在 Runtime 進行派發的。

最底層的轉發函數為objc_msgSend。

使用 performSelector 可以給對象發送消息,但是其有幾個短板

  • 在 ARC 場景下 performSelector 可能會造成內存洩漏
  • performSelector 至多接收 2 個參數,如果參數多餘 2 個,我們就無法使用 performSelector 來向對象發送消息了。
  • performSelector 限制參數類型為 id,以標量數據(int double NSInteger 等)為參數的方法使用 performSelector 調用會出現各種各樣詭異的問題

NSInvocation 是蘋果工程師們提供的一個高層的消息轉發系統。它是一個命令對象,是一個消息調用類,可以給任何 Objective-C 對象類型發送消息。

NSInvocation 包含了所有OC消息的成分:target、selector、參數、返回值等。NSInvocation可以將消息轉換成一個對象,消息的每一個參數能夠直接設定,而且當一個NSInvocation對象調度時返回值是可以自己設定的。一個NSInvocation對象能夠重複的調度不同的目標(target),而且它的selector也能夠設置為另外一個方法簽名。

NSInvocation 的使用

使用步驟:

創建方法創建簽名對象NSMethodSignature
根據簽名對象創建調用NSInvocation
設置調用對象相關信息
調用方法
獲取返回值
無參數、無返回值

無參數、無返回值 的 對應代碼為:

- (void)startTest_Imple
{
// 獲取方法簽名
NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:@selector(startTest)];
// 生成調用對象
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
// 設置target
invocation.target = self;
// 設置方法實現
invocation.selector = @selector(startTest);
// 調用
[invocation invoke];
}

- (void)startTest
{
NSLog(@"無參數、無返回值:startTest_1");
}

兩個個參數、有返回值的代碼為:

- (void)startTest_Imple_3
{
// 獲取方法簽名
NSMethodSignature *signature = [ViewController instanceMethodSignatureForSelector:@selector(startTest_3:text1:)];
// 生成調用對象
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
// 設置target
invocation.target = self;
// 設置方法實現
invocation.selector = @selector(startTest_3:text1:);
// 設置參數,參數必須從2開始,第一個第二個參數為target和selector
NSString *argument = @"參數1";
NSString *argument1 = @"參數2";
[invocation setArgument:&argument atIndex:2];
[invocation setArgument:&argument1 atIndex:3];
// 調用
[invocation invoke];
NSString *returnValue = nil;
[invocation getReturnValue:&returnValue];
NSLog(@"返回值:%@",returnValue);
}
- (NSString *)startTest_3:(NSString *)text text1:(NSString *)text1
{
NSLog(@"參數%@--%@,無返回值:startTest_1",text,text1);
return @"返回值";
}

具體實例,下面用NSInvocation方式來調用sendMessageWithNumber方法。

- (void)viewDidLoad {
[super viewDidLoad];
//NSInvocation;用來包裝方法和對應的對象,它可以存儲方法的名稱,對應的對象,對應的參數,
/*
NSMethodSignature:簽名:再創建NSMethodSignature的時候,必須傳遞一個簽名對象,簽名對象的作用:用於獲取參數的個數和方法的返回值

*/
//創建簽名對象的時候不是使用NSMethodSignature這個類創建,而是方法屬於誰就用誰來創建
NSMethodSignature*signature = [ViewController instanceMethodSignatureForSelector:@selector(sendMessageWithNumber:WithContent:)];

//1、創建NSInvocation對象
NSInvocation*invocation = [NSInvocation invocationWithMethodSignature:signature];

invocation.target = self;

//invocation中的方法必須和簽名中的方法一致。
invocation.selector = @selector(sendMessageWithNumber:WithContent:);

/*第一個參數:需要給指定方法傳遞的值
第一個參數需要接收一個指針,也就是傳遞值的時候需要傳遞地址*/
//第二個參數:需要給指定方法的第幾個參數傳值
NSString*number = @"1111";

//注意:設置參數的索引時不能從0開始,因為0已經被self佔用,1已經被_cmd佔用
[invocation setArgument:&number atIndex:2];

NSString*number2 = @"啊啊啊";

[invocation setArgument:&number2 atIndex:3];

//2、調用NSInvocation對象的invoke方法
//只要調用invocation的invoke方法,就代表需要執行NSInvocation對象中制定對象的指定方法,並且傳遞指定的參數
[invocation invoke];
}
- (void)sendMessageWithNumber:(NSString*)number WithContent:(NSString*)content{
NSLog(@"電話號%@,內容%@",number,content);

}
iOS開發之-NSInvocation


分享到:


相關文章: