簡體   English   中英

在Objective-C中,如果@property和@synthesize將添加getter和setter,為什么不公開實例變量呢?

[英]In Objective-C, if @property and @synthesize will add getter and setter, why not just make an instance variable public?

在Objective-C中,我們可以添加@property@synthesize來創建一個屬性 - 就像一個帶有getter和setter的實例變量,這些變量對這個類的用戶是公開的。

在這種情況下,是否與聲明實例變量並將其公開一樣? 然后就不會有將getter和setter作為方法調用的開銷。 我們可能有可能對setter進行驗證,例如將數字限制在0到100之間,但除此之外,公共實例變量不會實現同樣的事情,而且更快嗎?

即使您只使用@synthesize生成的訪問器,它們也會為您帶來以下好處:

  1. 內存管理:生成的setter保留(retain)屬性的新值。 如果您嘗試直接從類外部訪問對象ivar,則不知道該類是否可以保留它。 (這不是ARC的問題,但仍然很重要。)

  2. Threadsafe訪問:默認情況下,生成的訪問器是原子的,因此您不必擔心從多個線程訪問該屬性的競爭條件。

  3. 鍵值編碼和觀察: KVC可在各種情況下方便地訪問您的屬性。 您可以在設置謂詞時使用KVC(例如,用於過濾對象的集合),或者使用鍵路徑獲取集合中的屬性(例如,包含類的對象的字典)。 KVO允許程序的其他部分自動響應屬性值的變化 - 這在Mac上與Cocoa Bindings一起使用很多,你可以將控件綁定到屬性的值,也可以在Core Data中使用兩個平台。

除此之外,屬性還提供封裝。 使用類實例的其他對象(客戶端)不必知道您是否正在使用生成的訪問器 - 您可以創建自己的訪問器來執行其他有用的操作,而無需客戶端代碼進行更改。 在某些時候,您可能會決定您的課程需要對其中一個ivars的外部更改作出反應:如果您已經使用了訪問者,則只需要更改它們,而不是讓您的客戶開始使用它們。 或者,Apple可以在未來的操作系統版本中以更好的性能或新功能改進生成的訪問器,並且您的其他類代碼或其客戶端都不需要更改。

開銷不是真正的問題

為了回答你的上一個問題,是的,會有開銷 - 但是推動一個框架並將其從堆棧中彈出的開銷可以忽略不計,特別是考慮到現代處理器的強大功能。 如果你關心性能,你應該分析你的應用程序並確定實際問題的位置 - 我保證你會找到比刪除一些訪問器更好的優化位置。

這是好設計

封裝您的私有成員並使用訪問器和更改器保護它們只是良好軟件設計的基本原則:它使您的軟件更易於維護,調試和擴展。 您可能會問任何其他語言的相同問題:例如,為什么不在Java類中公開所有字段? (我想,除了像Ruby這樣的語言,這使得無法公開實例變量)。 最重要的是,某些軟件設計實踐已經到位,因為隨着您的軟件變得越來越大,您將從一個名副其實的地獄中拯救自己。

延遲加載

在setter中驗證是一種可能性,但你可以做的更多。 您可以覆蓋getter以實現延遲加載。 例如,假設您有一個必須從文件或數據庫加載某些字段的類。 傳統上這是在初始化時完成的。 但是,實例化對象的人可能並不會實際使用所有字段,因此您需要等待初始化這些成員,直到通過getter請求它們為止。 這樣可以清除初始化,並且可以更有效地利用處理時間。

有助於避免在ARC中保留周期

最后,屬性使得更容易避免在ARC下使用塊保留循環。 ivars的問題在於,當您訪問它們時,您隱式引用self。 所以,當你說:

_foo = 7;

你真正說的是

self->_foo = 7;

所以說你有以下內容:

[self doSomethingWithABlock:^{
    _foo = 7;
}];

你現在已經有了一個保留周期。 你需要的是一個弱指針。

__block __weak id weakSelf = self;
[self doSomethingWithABlock:^{
    weakSelf->_foo = 7;
}];

現在,顯然這仍然是setter和getter的問題,但是你不太可能忘記使用weakSelf,因為你必須明確地調用self.property,而ivars是自我引用的。 如果您正在使用屬性,靜態analayzer將幫助您解決此問題。

@property是一個已發布的事實。 它告訴其他類他們可以獲得並可能設置該類的屬性。 屬性不是變量,它們實際上就是單詞所說的。 例如, countNSArray的屬性。 它必然是一個實例變量嗎? 沒有。沒有理由你應該關心它是否是。

@synthesize創建一個默認的getter,setter和instance變量,除非你自己定義了這些東西。 這是一個特定的實現。 這是您的班級選擇履行其提供財產的合同義務的方式。 它只是提供屬性的一種方式,您可以隨時更改您的實現,而無需告訴其他任何人。

那么為什么不公開實例變量而不是提供getter和setter呢? 因為那束縛了你對班級的實施。 它使其他行為依賴於編碼的特定方式,而不僅僅是您選擇為其發布的接口。 這很快就會產生脆弱且相互依賴的代碼。 這是面向對象編程的詛咒。

因為人們通常會對封裝和隱藏數據和實現感興趣。 它更容易維護; 您必須更改一個實現,而不是全部 實施細節對客戶端隱藏。 此外,客戶端不應該考慮該類是否是派生類。

你是對的......對於一些非常有限的案例。 當它們用於像素,圖像和實時音頻DSP(等)代碼的內部循環時,屬性在CPU循環性能方面是可怕的。 對於較不頻繁的使用,它們在可讀的可維護可重用代碼方面帶來許多好處。

@property和@synthesize設置正在獲取getter和setter方法

其他用法是你也可以在其他類中使用該變量

如果你想使用變量作為實例變量和你的自定義getter和setter方法,你可以做但有時你設置變量的值,而檢索變量的值有時會變成僵屍,這可能會導致你的應用程序崩潰。

所以該屬性將告訴操作系統不要釋放對象,直到你釋放你的對象為止,希望它有所幫助

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM