1. 程式人生 > >performSelector呼叫和直接呼叫的區別

performSelector呼叫和直接呼叫的區別

原文連結:http://www.cnblogs.com/agger0207/p/4426131.html

今天在準備出筆試題的過程中隨便搜了一下其他的筆試題,看到其中一個就是關於performSelector與直接呼叫的區別。

個人感覺這其實是一個陷阱題,因為大部分應用場景下,用哪一種都可以,可以說是沒有區別的,但其實又有一些細節上的區別。

比如說,假如有如下程式碼:

複製程式碼
- (void)doTest {

    Student* student = [[Student alloc] init];

    [student performSelector:@selector(doSomething)];

    [student doSomething];

}
複製程式碼

具體執行過程中的區別道理是什麼呢?

還是先看官方文件對performSelector的描述:

- (id)performSelector:(SEL)aSelector

Description

Sends a specified message to the receiver and returns the result of the message. (required)

The performSelector: method is equivalent to sending an aSelector message directly to the receiver. For example, all three of the following messages do the same thing:

id myClone = [anObject copy];

id myClone = [anObject performSelector:@selector(copy)];

id myClone = [anObject performSelector:sel_getUid("copy")];

However, the performSelector: method allows you to send messages that aren’t determined until runtime A variable selector can be passed as the argument:

SEL myMethod = findTheAppropriateSelectorForTheCurrentSituation();

[anObject performSelector:myMethod];

The aSelector argument should identify a method that takes no arguments. For methods that return anything other than an object, use NSInvocation.

核心的就那麼幾句:

1 執行的效果其實和傳送訊息是等價的;

2 performSelector允許傳送未在執行時確定的訊息;也就是說,只要這個訊息能夠被轉發到正確的接收者,能夠被最後的接收者識別,都是可以正確執行的。否則,就會在執行時報錯“unrecognized selector sent to instance”.

具體來說:假如上面的Student的定義和實現如下:

複製程式碼
@interface Student : NSObject

- (void)doSomething;

@end

@implementation Student

- (void)doSomething {

    NSLog(@"doSomething");

}

@end
複製程式碼

那麼這兩者基本上是等價的;但是,假如doSomething是一個私有的方法呢? 可以試著將這個方法從標頭檔案中刪除如下:

@interface Student : NSObject

@end

這個時候[student doSomething];就會在編譯時候報錯啦!

而對於performSelector呢,僅僅當編譯警告選項“Undeclared Selector”開啟的時候才會有編譯警告。

另外,即使這個方法並沒有實現,也就是說從.m檔案中刪除這個方法,編譯是可以通過的,但是執行時會Crash,報的錯誤就是剛才的“unrecognized selector sent to instance”.

我自己由於是從C++程式設計師轉過來的,所以其實更喜歡[student doSomething]這種方法,一旦有問題的時候,在編譯期間就很容易發現啦!

但Obejct-C的動態特性是允許在執行時向某個類新增方法的,這個時候就一定需要使用performSelector了。那麼為了避免執行時出現錯誤,在使用performSelector之前一定要使用如下的檢查方法來進行判斷。

- (BOOL)respondsToSelector:(SEL)aSelector;

The End.