performSelector的原理以及用法


一、performSelector調用和直接調用區別
下面兩段代碼都在主線程中運行,我們在看別人代碼時會發現有時會直接調用,有時會利用performSelector調用,今天看到有人在問這個問題,我便做一下總結,
[delegate imageDownloader:self didFinishWithImage:image];
[delegate performSelector:@selector(imageDownloader:didFinishWithImage:)withObject:self withObject:image];

1、performSelector是運行時系統負責去找方法的,在編譯時候不做任何校驗;如果直接調用編譯是會自動校驗。如果imageDownloader:didFinishWithImage:image:不存在,那么直接調用 在編譯時候就能夠發現(借助Xcode可以寫完就發現),但是使用performSelector的話一定是在運行時候才能發現(此時程序崩潰);Cocoa支持在運行時向某個類添加方法,即方法編譯時不存在,但是運行時候存在,這時候必然需要使用performSelector去調用。所以有時候如果使用了performSelector,為了程序的健壯性,會使用檢查方法- (BOOL)respondsToSelector:(SEL)aSelector;

2、直接調用方法時候,一定要在頭文件中聲明該方法的使用,也要將頭文件import進來。而使用performSelector時候,可以不用import頭文件包含方法的對象,直接用performSelector調用即可。


二、常用的performSelector簡單分析
1.
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
這三個方法,均為同步執行,與線程無關,主線程和子線程中均可調用成功。等同於直接調用該方法。在需要動態的去調用方法的時候去使用。
例如:[self performSelector:@selector(test2)];與[self test2];執行效果上完全相同。

2.
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray *)modes;
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;
這兩個方法為異步執行,即使delay傳參為0,仍為異步執行。只能在主線程中執行,在子線程中不會調到aSelector方法。可用於當點擊UI中一個按鈕會觸發一個消耗系統性能的事件,在事件執行期間按鈕會一直處於高亮狀態,此時可以調用該方法去異步的處理該事件,就能避免上面的問題。
在方法未到執行時間之前,取消方法為:
+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget selector:(SEL)aSelector object:(id)anArgument;
+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget;
注意:調用該方法之前或在該方法所在的viewController生命周期結束的時候去調用取消函數,以確保不會引起內存泄露。

3.
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
這兩個方法,在主線程和子線程中均可執行,均會調用主線程的aSelector方法;
如果設置wait為YES:等待當前線程執行完以后,主線程才會執行aSelector方法;
設置為NO:不等待當前線程執行完,就在主線程上執行aSelector方法。
如果,當前線程就是主線程,那么aSelector方法會馬上執行。
注意:apple不允許程序員在主線程以外的線程中對ui進行操作,此時我們必須調用performSelectorOnMainThread函數在主線程中完成UI的更新。

4.
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
調用指定線程中的某個方法。分析效果同3。

5.
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg
開啟子線程在后台運行

三、示例
首先建立一個簡單的函數
- (void) fooNoInputs {
NSLog(@"Does nothing");
}
然后調用它[self performSelector:@selector(fooNoInputs)];

第二個試驗看看如何在消息中傳遞參數
我們建立一個有input參數的函數
- (void) fooOneIput:(NSString*) first {
NSLog(@"Logs %@", first);
}
然后調用它[self performSelector:@selector(fooOneInput:) withObject:@"first"];

第三個試驗更多的參數
- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second {
NSLog(@"Logs %@ then %@", first, second);
}
然后調用它
[self performSelector:@selector(fooFirstInput:secondInput:) withObject:@"first" withObject:@"second"];
第四個試驗如何建立動態的函數,然后調用他們?我們需要建立一個selector
SEL myTestSelector = @selector(myTest:);
並且我們調用的函數在另外一個Class內
- (void)abcWithAAA: (NSNumber *)number {
int primaryKey = [number intValue];
NSLog("%i", primaryKey);
}
MethodForSelectors * mfs = [[MethodForSelectors alloc]init];
NSArray *Arrays = [NSArray arrayWithObjects:@"AAA", @"BBB", nil];
for ( NSString *array in Arrays ){
SEL customSelector = NSSelectorFromString([NSStringstringWithFormat:@"abcWith%@:", array]);
mfs = [[MethodForSelectors alloc] performSelector:customSelector withObject:0];
}
注意:updated at 20120606

1.如果使用了ARC會產生“performSelector may cause a leak because its selector is unknown”警告
2.這種方式當傳入一個不符合約定的消息時會繼續運行並不報錯。例如應該傳入2個參數,但只傳入1個參數。或傳入了3個參數,第三個參數不會被初始化。
還有一種調用其他Class Function的方法是,但是不能有參數,我們這里假設沒有參數,那么就可以這樣[mfs customSelector]; 

完整的代碼:


@implementation ClassForSelectors
- (void) fooNoInputs {
NSLog(@"Does nothing");
}
- (void) fooOneIput:(NSString*) first {
NSLog(@"Logs %@", first);
}
- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second {
NSLog(@"Logs %@ then %@", first, second);
}
 
- (NSArray *)abcWithAAA: (NSNumber *)number {
int primaryKey = [number intValue];
NSLog("%i", primaryKey);
}
 
- (void) performMethodsViaSelectors {
[self performSelector:@selector(fooNoInputs)];
[self performSelector:@selector(fooOneInput:) withObject:@"first"];
[self performSelector:@selector(fooFirstInput:secondInput:) withObject:@"first" withObject:@"second"];
}
 
- (void) performDynamicMethodsViaSelectors {
MethodForSelectors * mfs = [MethodForSelectors alloc];
NSArray *Arrays = [NSArray arrayWithObjects:@"AAA", @"BBB", nil];
for ( NSString *array in Arrays ){
SEL customSelector = NSSelectorFromString([NSStringstringWithFormat:@"abcWith%@:", array]);
mfs = [[MethodForSelectors alloc] performSelector:customSelector withObject:0];
}
}
@end
 
@implementation MethodForSelectors
- (void)abcWithAAA: (NSNumber *)number {
NSLog("%i", number);
}
@end


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM