2011-03-21 48 views
6

如果我想定義一個自定義的UIView子類,當它的邊界被設置時執行某些操作,我該如何覆蓋setter?覆蓋setBounds看起來很危險,因爲如果我理解正確,getter和setter名稱不是公共接口的一部分,並且可以隨時更改。我該如何幹淨地重寫屬性setter?

當然,我使用class_copyPropertyList來查詢運行時查找類中定義的屬性列表,然後查詢setter的名稱,最後使用class_addMethod在第一次獲得對先前方法的引用後添加該方法用於調用原始版本。

所有這些看起來都很糟糕。有沒有一種乾淨的方式來做我想做的事情,保證在未來的操作系統版本上不會中斷?謝謝。

+1

bounds屬性在UIView頭文件中定義,因此您的評論「getter和setter名稱不是公共接口的一部分,並且可以隨時更改」不是true:'@property(nonatomic)CGRect bounds'這意味着getter/setter是'bounds' /'setBounds:' – 2011-03-21 17:28:43

+0

實例變量也在頭文件中聲明,但這並不意味着它們是公共接口的一部分:)是否準確地說出http:// developer.apple.com/library/ios/#documentation/uikit/reference/UIView_Class/UIView/UIView.html是公共界面嗎?這沒有提到setBounds。 – 2011-03-22 06:25:24

回答

19

您可以覆蓋一個setter /吸氣,而無需閒逛類的內部狀態(即高德) - 只是調用父類的方法,你的覆蓋:

- (Thing *)thing { 
    // do your extra stuff here 
    // ... 

    return [super thing]; 
} 

- (void)setThing:(Thing *)thing { 
    // do your extra stuff here 
    // ... 

    [super setThing:thing]; 
} 

一種可能適合的替代你問題是使用KVO

更新

當然,覆蓋setBounds可能沒有必要。請參閱this question - 如果幀發生更改,則會調用layoutSubviews,並且更改邊界會導致幀大小也被更新。所以考慮把你的代碼放入layoutSubviews

最後更新

好了,這是爲什麼蘋果永遠不會突然宣佈一些@property項目,如使用非標準方法的名稱(如你擔心):

這將打破一切應用商店。

想想這樣:在編譯時,任何使用點符號訪問屬性的代碼,例如語法糖obj.x被轉換爲形式[obj x]的消息。同樣對於屬性 - 它們在編譯時轉換爲常規方法。所以,編譯的二進制文件對點符號和屬性一無所知 - 它們只是調用常規選擇器。因此,如果Apple發佈iOS更新,宣佈某些公共屬性具有非標準實現方法,則應用程序商店中的所有內容都可能會中斷。一切。在這種情況下,如果你的應用崩潰了,那麼在這種情況下就沒有任何問題 - 這將是蘋果的錯,而不是你的。

+0

這沒有解決我的問題 - 如果setter名稱更改爲iOS 5中的setViewBounds會怎麼樣?我沒有在UIView文檔的任何位置找到名稱爲setBounds的http://developer.apple.com/library/ios/#documentation/uikit/reference/UIView_Class/UIView/UIView.html,所以我不相信我可以依靠它。我錯過了什麼嗎? – 2011-03-22 06:26:44

+0

換句話說,設置者名稱是該類內部狀態的一部分。 – 2011-03-22 06:27:14

+0

@ kartick-vaddadi setter名稱來源於已發佈的API的屬性「bounds」,因此非常不可能無故更改。 setter名稱的模式是'setX' - 這不會改變,因爲絕對一切都會到處打破,而不僅僅是您的代碼!我非常有信心,'setBounds'和'bounds'方法不會變成別的東西。 – occulus 2011-03-22 15:09:41

2
@property(nonatomic) CGRect bounds; 

-(CGRect)bounds; 
-(void)setBounds:(CGRect)bounds; 

速記,

view.bounds = rect; 

[view setBounds:rect]; 

速記,

CGRect rect = view.bounds; 

CGRect rect = [view bounds]; 

點符號和@property聲明速記是語法糖。它們用於縮短代碼和方便程度。消息和選擇器總是在它們的下面,並且始終可以依賴它們成爲界面中穩定的,即使不是最穩定的部分。

覆蓋「setBounds:」是一種安全的方法。 「setBounds:」在公共接口中未明確命名,因爲它被聲明爲@property。然而,標準是,帶有「set」 - 資本化屬性名稱的setter總是被創建(除非它是隻讀的)。

+0

請參閱我上面的意見。 @property可以更改爲使用不同的設置者名稱。 – 2011-03-22 06:27:48

+0

是的,但蘋果不會這樣做,因爲它會破壞很多東西。他們更有可能更改內部伊娃變量名稱(這對您而言是隱藏的),但只留下公共屬性名稱。 – occulus 2011-03-22 15:13:34

+0

@ kartick-vaddadi它是接口聲明的一部分,它是與圖書館消費者建立的合同。它可以安全地依賴於任何其他對象或功能。您可能擔心整個框架中的每個方法名稱。 – 2011-03-22 20:47:24

0

OSX中有一個NSViewBoundsDidChange通知。這似乎是更好的解決方案,雖然擔心重寫@property方法似乎沒有根據。我在這篇文章中遇到了關於覆蓋訪問者的相同問題,並且您確信我傾向於通知。