2015年7月7日 星期二

[筆記] iOS 使用 Sending Messages 該注意的小細節

今天遇到一個 Crash 的問題,是呼叫關於 Sending Messages 這系列的 API:
- performSelector:
- performSelector:withObject:
- performSelector:withObject:withObject:

一開始也是一頭霧水,一樣請出大神拜一下,在 stackoverflow 找到了解答!

文章提到,根據 Apple 文件上的記載:
「For methods that return anything other than an object, use NSInvocation.」

也就是說當你呼叫這系列 API 的時候,請記得如果你呼叫的介面並不回傳物件,而是其他像是 BOOL, NSInteger...之類的型別,那就要改使用 NSInvocation 來解決你的需求!

這是我遇到的狀況就是回傳 BOOL 型別,我一開始根據某篇一樣在 stackoverflow 的文章(我已經忘記連結了),認為這系列的 API 會將 BOOL 包裝成 NSNumber 物件,所以我哏開心的把公司程式中的邏輯變更掉,結果 QA 回報說會 Crash,真是踩到了地雷阿!

NSInvocation 是用起來也不困難,另有一篇 stackoverflow 的文章寫了一個範例,這裡把它列出來做個記錄:
SEL selector = NSSelectorFromString(@"someSelector");
if ([someInstance respondsToSelector:selector]) {
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:
                                [[someInstance class] instanceMethodSignatureForSelector:selector]];
    [invocation setSelector:selector];
    [invocation setTarget:someInstance];
    [invocation invoke];
    float returnValue;
    [invocation getReturnValue:&returnValue];
    NSLog(@"Returned %f", returnValue);
}

在沒有去看文件的狀況之下,這的確蠻容易被忽略的~畢竟不管它似乎也好像是對的!但這就是隱藏地雷阿!

所以不要再一股腦兒用 performSelector 了!記得也要根據實際狀況變更呼叫的 API!

參考資料:
How to return any type value like -performSelector?
Return value for performSelector: