2012-11-02 46 views
7

上執行主線程方法,我碰到這個_cmd招進來:使用_cmd在目標C

-(void)methodToBeRunOnMainThreadWithObj:(id)object { 
    if (![NSThread isMainThread) { 
     [self performSelectorOnMainThread:_cmd withObject:object] 
    } else { 
     // ... method body 
    } 
} 

這是爲了確保一個方法可靠的方法是在主線程上執行?

+0

多麼可愛的把戲! – Gerstmann

回答

7

這工作,但它是一個有點反模式。如果調用方法的線程不是主線程,我會做的就是拋出一個錯誤。調用者有責任確保在正確的線程上調用方法,這些類型的黑客只會鼓勵難看的代碼。此外,如果你依賴於這個,突然間你每次調用這個方法都會使消息調度開銷加倍。

如果你真的不能改變調用者的行爲,你可以嘗試以下方法:

-(void)methodToBeRunOnMainThreadWithObj:(id)object { 
    dispatch_sync(dispatch_get_main_queue(), ^{ 
     // code goes here 
    }); 
} 

這將導致在主線程中執行的調度塊內的所有代碼,並且該方法不會返回,直到它是完整的。如果您希望立即返回該方法,則可以使用dispatch_async代替。如果你使用dispatch_sync,你甚至可以在具有非void返回類型的方法上使用這個技巧。

此代碼還具有支承與是非對象類型(int等)的參數的方法的額外益處。它也支持具有任意數量參數的方法,而performSelector:withObject:及其兄弟方法僅支持有限數量的參數。另一種方法是設置NSInvocation對象,這是一種痛苦。

注意,這需要大中央調度(GCD)你的平臺上。

+0

+1類型安全替代 – justin

3

_cmd轉發是細的,只要由_cmd的指定選擇的文檔中指定的定義/簽名相匹配:「的方法不應該有一個顯著返回值,並應採取類型ID的單個參數,或不論據「。。如果它不匹配,那麼你應該假設未定義的行爲。而且是110%安全,堅持以抽象機,返回類型應該是id(或某些objc型),結果不應該返回所屬的參考。

+1

+1注意限制。我忽略了返回類型問題我的答案,因爲在這個問題原來的方法是'void',但OP似乎在尋找一個通用的解決方案,而'performSelector'是一個也沒有。 – yfrancis

+0

@yfrancis我最初避免提及返回類型以及:)但我在編輯中添加了一點。 – justin