iOS 方法調(diào)用的三張方式

? ? ? ? 在iOS中調(diào)用一個方法,基本上有三種調(diào)用方式:①直接用對應類調(diào)用對應的類方法改艇,類對象調(diào)用對象方法霍殴。②使用performSelector的方式調(diào)用。③使用NSInvocation去調(diào)用方法拼苍。

一、直接用對應類調(diào)用對應的類方法调缨,類對象調(diào)用對象方法疮鲫。

? ? ? ? 這是iOS中最經(jīng)常使用的方法調(diào)用方式,即消息機制弦叶。
? ? ? ? 舉例: 自定義類 SomeObject

?[SomeObject? Test];? // 類方法的調(diào)用
SomeObject *someOb = [[SomeObject alloc] init];?
?[someOb test]; ?// 對象方法的調(diào)用

? ? ? ? 這種調(diào)用方式外界在調(diào)用時必須要引入對應的類俊犯,其方法必須在該類的.h文件中聲明。

二伤哺、使用performSelector的方式調(diào)用燕侠。

[delegate imageDownloader:self didFinishWithImage:image];
[delegate performSelector:@selector(imageDownloader:didFinishWithImage:) ? ?withObject:self ?withObject:image]者祖;

1、performSelector是運行時系統(tǒng)負責去找方法的贬循,在編譯時候不做任何校驗咸包;如果直接調(diào)用編譯是會自動校驗。如果imageDownloader:didFinishWithImage:image:不存在杖虾,那么直接調(diào)用在編譯時候就能夠發(fā)現(xiàn)(借助Xcode可以寫完就發(fā)現(xiàn))烂瘫,但是使用performSelector的話一定是在運行時候才能發(fā)現(xiàn)(此時程序崩潰);Cocoa支持在運行時向某個類添加方法奇适,即方法編譯時不存在坟比,但是運行時候存在,這時候必然需要使用performSelector去調(diào)用嚷往。所以有時候如果使用了performSelector葛账,為了程序的健壯性,會使用檢查方法

- (BOOL)respondsToSelector:(SEL)aSelector;

2皮仁、直接調(diào)用方法時候籍琳,一定要在頭文件中聲明該方法的使用,也要將頭文件import進來贷祈。而使用performSelector時候趋急,可以不用import頭文件包含方法的對象,直接用performSelector調(diào)用即可势誊。

三呜达、使用NSInvocation去調(diào)用方法

? ? ? ? 第二種方式調(diào)用方法其作用很相似與函數(shù)指針,通過performSelector:withObject:函數(shù)可以直接調(diào)用這個消息粟耻。但是perform相關的這些函數(shù)查近,有一個局限性,其參數(shù)數(shù)量不能超過2個挤忙,否則要做很麻煩的處理霜威,與之相對,NSInvocation也是一種消息調(diào)用的方法册烈,并且它的參數(shù)沒有限制戈泼。

一、初始化與調(diào)用

在官方文檔中有明確說明茄厘,NSInvocation對象只能使用其類方法來初始化矮冬,不可使用alloc/init方法谈宛。它執(zhí)行調(diào)用之前次哈,需要設置兩個方法:setSelector: 和setArgument:atIndex:

- (void)viewDidLoad {
? ? [super viewDidLoad];
? ? //創(chuàng)建一個函數(shù)簽名,這個簽名可以是任意的,但需要注意吆录,簽名函數(shù)的參數(shù)數(shù)量要和調(diào)用的一 致窑滞。?
? ? SEL myMethod =@selector(myLog);
? ? //通過簽名初始化
? ? NSMethodSignature* sig? = [NSNumber instanceMethodSignatureForSelector:@selector(init)];
? ? NSInvocation* invocatin = [NSInvocation invocationWithMethodSignature:sig];
? ? //設置target
? ? [invocatin setTarget:self];
? ?//設置selecteor
? ?[invocatin setSelector:myMethod];
? //消息調(diào)用
? [invocatin invoke];
}
-(void)myLog{
? ?NSLog(@"MyLog");
}

注意:簽名函數(shù)的參數(shù)數(shù)量要和調(diào)用函數(shù)的一致。測試后發(fā)現(xiàn),當簽名函數(shù)參數(shù)數(shù)量大于被調(diào)函數(shù)時哀卫,也是沒有問題的巨坊。

調(diào)用多參數(shù)的方法,我們可以這樣寫:

-?(void)viewDidLoad?{????
? ? [superviewDidLoad];????
? ? SEL?myMethod?=@selector(myLog:parm:parm:);
? ? ?NSMethodSignature*?sig??=?[[selfclass]?instanceMethodSignatureForSelector:myMethod];
? ? ?NSInvocation*?invocatin?=?[NSInvocationinvocationWithMethodSignature:sig];????
? ? ?[invocatin?setTarget:self];????
? ? ?[invocatin?setSelector:myMethod2];
? ? ?inta=1;intb=2;intc=3;????
? ? ?[invocatin?setArgument:&a?atIndex:2];????
? ? [invocatin?setArgument:&b?atIndex:3];????
? ? [invocatin?setArgument:&c?atIndex:4];
? ? [invocatin?invoke];
}
-(void)myLog:(int)a?parm:(int)b?parm:(int)c{
? ? NSLog(@"MyLog%d:%d:%d",a,b,c);
}

注意:1此改、這里設置參數(shù)的Index 需要從2開始趾撵,因為前兩個被selector和target占用。下面這樣寫也沒有任何問題:

-?(void)viewDidLoad?{? ?
? ? [superviewDidLoad];
? ? SEL?myMethod?=@selector(myLog:parm:parm:);

? ? SEL?myMethod2?=@selector(myLog);
? ? NSMethodSignature*?sig??=?[[selfclass]?instanceMethodSignatureForSelector:myMethod];
? ? NSInvocation*?invocatin?=?[NSInvocationinvocationWithMethodSignature:sig];
? ? ViewController?*?view?=self;
? ? [invocatin?setArgument:&view?atIndex:0];
? ? [invocatin?setArgument:&myMethod2?atIndex:1];
? ? inta=1;intb=2;intc=3;
? ? [invocatin?setArgument:&a?atIndex:2];?
? ? [invocatin?setArgument:&b?atIndex:3];
? ? [invocatin?setArgument:&c?atIndex:4];
? ? [invocatin?retainArguments];
? ? [invocatin?invoke];}
-(void)myLog:(int)a?parm:(int)b?parm:(int)c{
? ? NSLog(@"MyLog%d:%d:%d",a,b,c);
}

2共啃、這里的傳參方式必須是傳遞參數(shù)地址占调。

二、NSInvocation的返回值

NSInvocation對象移剪,是可以有返回值的究珊,然而這個返回值,并不是其所調(diào)用函數(shù)的返回值纵苛,需要我們手動設置:

-?(void)viewDidLoad?{
? ? [superviewDidLoad];
? ? SEL?myMethod?=@selector(myLog:parm:parm:);
? ? NSMethodSignature*?sig??=?[[selfclass]?instanceMethodSignatureForSelector:myMethod];
? ?NSInvocation*?invocatin?=?[NSInvocationinvocationWithMethodSignature:sig];
? ? [invocatin?setTarget:self];
? ? [invocatin?setSelector:myMethod2];
? ? ViewController?*?view?=self;
? ? inta=1;intb=2;intc=3;
? ? [invocatin?setArgument:&view?atIndex:0];
? ? [invocatin?setArgument:&myMethod2?atIndex:1];
? ? [invocatin?setArgument:&a?atIndex:2];
? ? [invocatin?setArgument:&b?atIndex:3];
? ? [invocatin?setArgument:&c?atIndex:4];
? ? [invocatin?retainArguments];//我們將c的值設置為返回值
? ?[invocatin?setReturnValue:&c];
? ?int d;//取這個返回值
? ? [invocatin?getReturnValue:&d];
? NSLog(@"%d",d);
}
-(int)myLog:(int)a?parm:(int)b?parm:(int)c{
? ? NSLog(@"MyLog%d:%d:%d",a,b,c);
? ? returna+b+c;
}

注意:這里的操作傳遞的都是地址剿涮。如果是OC對象,也是取地址攻人。

三取试、關于內(nèi)存

可以注意到- (void)retainArguments;這個方法,它會將傳入的所有參數(shù)以及target都retain一遍贝椿。

總結:

平時開發(fā)中基本很少使用后邊兩張方式想括,但是假如想要修改一些系統(tǒng)方法的私有屬性,或者調(diào)用私有方法時直接調(diào)用顯然是無法滿足需求的此時就需要使用上邊的方式調(diào)用了烙博。第二種方式相較于第三種方式更加簡單一些瑟蜈,但是其局限性就是無法調(diào)用太多參數(shù)的方法,或者參數(shù)是非object對象的參數(shù)渣窜。第三類方法基本可以實現(xiàn)所有方法調(diào)用铺根,缺點就是比較繁瑣。

使用第三類方法解決問題的實際案例
Hacky way 解決 iOS 7 UISearchBar 默認文本居左展示問題


最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末乔宿,一起剝皮案震驚了整個濱河市位迂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌详瑞,老刑警劉巖掂林,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異坝橡,居然都是意外死亡泻帮,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門计寇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锣杂,“玉大人脂倦,你說我怎么就攤上這事≡” “怎么了赖阻?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長踱蠢。 經(jīng)常有香客問我火欧,道長,這世上最難降的妖魔是什么茎截? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任布隔,我火速辦了婚禮,結果婚禮上稼虎,老公的妹妹穿的比我還像新娘衅檀。我一直安慰自己,他們只是感情好霎俩,可當我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布哀军。 她就那樣靜靜地躺著,像睡著了一般打却。 火紅的嫁衣襯著肌膚如雪杉适。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天柳击,我揣著相機與錄音猿推,去河邊找鬼。 笑死捌肴,一個胖子當著我的面吹牛蹬叭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播状知,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼秽五,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了饥悴?” 一聲冷哼從身側響起坦喘,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎西设,沒想到半個月后瓣铣,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡贷揽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年棠笑,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片擒滑。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡腐晾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出丐一,到底是詐尸還是另有隱情藻糖,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布库车,位于F島的核電站巨柒,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏柠衍。R本人自食惡果不足惜洋满,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望珍坊。 院中可真熱鬧牺勾,春花似錦、人聲如沸阵漏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽履怯。三九已至回还,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間叹洲,已是汗流浹背柠硕。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留运提,地道東北人蝗柔。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像民泵,于是被迫代替她去往敵國和親诫咱。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,627評論 2 350

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