2011-02-05 19 views
6

我剛剛遇到在Three20一些代碼,看起來像這樣:爲什麼在運行時使用performSelector:withObject:withObject如果您在編譯時知道選擇器及其參數?

SEL sel = @selector(textField:didAddCellAtIndex:); 
    if ([self.delegate respondsToSelector:sel]) { 
    [self.delegate performSelector:sel withObject:self withObject:(id)_cellViews.count-1]; 
    } 

在LLVM 2.0,這會導致編譯錯誤:

error: arithmetic on pointer to interface 'id', which is not a constant size in non-fragile ABI

我知道這是爲什麼錯誤發生和我知道如何解決它。我只需要直接調用該方法,像這樣:

SEL sel = @selector(textField:didAddCellAtIndex:); 
    if ([self.delegate respondsToSelector:sel]) { 
    [self.delegate textField:self didAddCellAtIndex:(_cellViews.count - 1)]; 
    } 

我的問題是,如果你知道這兩個選擇和它在編譯時的參數,你爲什麼會需要在運行時使用performSelector:withObject:withObject:?我不明白爲什麼代碼是這樣寫的。如果選擇器和參數被動態傳遞到方法中,我可能會理解,但它們不是,選擇器和它的參數是硬編碼的(即使索引在運行時發生了變化,它獲取索引的方法很難編碼)。

如果有人可以向我解釋爲什麼這將是必要的一個很好的理由,我會很感激。否則,我會在這裏更改所有這些代碼。

回答

10

經過多一點挖掘,它看起來像TTPickerTextField類,該代碼可以找到是UITextField的間接子類。

因此,它在UITextField的代表性財產上揹負,這不符合TTPickerTextFieldDelegate協議,其中聲明瞭方法textField:didAddCellAtIndex:

我得出結論,這段代碼只是懶惰。沒有理由爲什麼UITextField的代表財產不得不捎帶,這使得這個令人困惑的,容易出錯的代碼變得必要。

我自己的做法是單獨保留UITextField的委託屬性,並將我自己的屬性添加到處理特定委託方法的特定子類中。

只是爲了澄清 - 我在問題中提到的「解決方案」修復編譯器錯誤,但生成的方法不能發現將被假定爲返回ID的警告。這是原始代碼「解決」的問題,但只適用於GCC。不再使用LLVM 2.0。

最後編輯,我承諾:

我的最終解決方案,以打擊這種懶惰和擺脫的警告和錯誤是一個醜陋的黑客攻擊:

[(id <TTPickerTextFieldDelegate>)self.delegate textField:self didAddCellAtIndex:(_cellViews.count - 1)]; 

演員UITextField小號委託給id符合到TTPickerTextFieldDelegate,然後直接調用該方法。

請不要偷懶:(

+0

Three20不應該傳遞一個整數值作爲指針。淘氣,淘氣。感謝您的修復。 – justice 2011-09-08 13:36:41

5

這respondsToSelector/performSelector組合是可選的委託方法的成語。委託是不能保證具有定義的方法,所以它直接調用將導致編譯器警告。

什麼編譯器實際上是在這種情況下抱怨:

[self.delegate performSelector:sel withObject:self withObject:(id)_cellViews.count-1]; 

error: arithmetic on pointer to interface 'id', which is not a constant size in non-fragile ABI 

是有風險的指針運算......「ID」爲指針類型,所以:

(id)_cellViews.count-1 

告訴它的編譯器要從一個指針中減去一個而不是一個整數....這可能不是該代碼的意圖。 performSelector的withObject參數必須是一個指針,它不能是原語。你可以通過在NSNumber中包裝_cellViews.count - 1來解決這個問題,並在委託方法中解開它。

[self.delegate performSelector:sel withObject:self withObject:[NSNumber numberWithInt:_cellViews.count-1]]; 
+0

我知道爲什麼編譯器原本是在抱怨,而這對原始代碼來說會是一個更好的方法,並且可能比我的工作更好。唯一的問題是這種類型的代碼在整個Three20庫中都存在,並且在這裏改變它需要在整個庫中改變它在哪裏使用。問題仍然是,原始代碼是懶惰寫的,對未來沒有任何先見之明。 – Jasarien 2011-02-05 17:48:36

相關問題