在 objective-c 的語言的早期,類的私有成員變數是只能定義在 .h 的標頭檔案裡面的。像如下這樣:
1
2
3
4
@inte***ce viewcontroller : uiviewcontroller
之後,蘋果改進了 objective-c,允許在 .m 裡面新增乙個特殊的匿名 category,即沒有名字的 category,來實現增加類的成員變數。像如下這樣: 1
2
3
@inte***ce viewcontroller ()
@property (nonatomic) nsinteger value;
@end
這樣的好處是,這些變數在標頭檔案中被徹底隱藏起來了,不用暴露給使用者。
接著,在 2013 年的 wwdc 中,蘋果進一步改進了 objective-c,允許在 .m 的 @implementation 中直接新增類的私有成員變數。像如下這樣:
1
2
3
@implementation viewcontroller
於是,大家對於如何定義私有的成員變數上就產生的分歧。許多人喜歡用匿名的 category 的方式來定義私有成員變數。但是,我個人更推薦在 @implementation 中直接新增類的私有成員變數。下面我做一些解釋。
歷史原因
首先早期的 ios 程式設計師一定知道,在 2011 年 arc 被推出之前,objective-c 是需要手工地管理引用計數的。而對類的所有私有成員使用 self.property 的形式,就可以使編譯器為我們自動生成管理引用計數的**。在 2012 年前,這個 feature 還需要使用 @synthesize 關鍵字來啟用的。於是,蘋果通過在**規範中推薦和強調使用 self.property 的程式設計習慣,來讓大家避免在記憶體管理中遇到問題。而在 arc 時代,這個程式設計習慣帶來的優勢不再存在了,因為編譯器會自動為我們管理引用計數,我們只需要關心不要造成迴圈引用問題就行了。
省心省事
剛剛說到,在類中完全使用 _property 的方式來訪問私有成員變數,是不會有記憶體管理上的問題的。但是使用 self.property 的方式來訪問私有變數是不是也是一樣不會有記憶體管理上的問題呢?確實也是,但是有一點需要注意:我們最好不要在 init 和 dealloc 中使用 self.property 的方式來訪問成員變數,這一點是寫在蘋果的官方文件裡的,我在以前的文章裡也介紹過。(見:《不要在init和dealloc函式中使用accessor》)
所以,如果你用 self.property 來訪問私有成員變數。那麼你需要注意,在 init 和 dealloc 中不使用這種方式。這其實對程式設計師來說是乙個負擔,你需要不停提醒自己有沒有犯錯。如果你使用完全的 _property 的方式來訪問私有成員變數,就不用想這一類問題了。
關於隱藏
大家知道,self.property 其實是呼叫了類的 [self property] 方法,所以這其實是有一層方法呼叫的隱藏,很多時候,我們需要延遲初使化乙個類成員的時候,就會把這個成員的初使化方法寫在這個 [self property] 方法的實現中。
那麼問題來了,當你在閱讀別人**時,看到 self.property 的時候,你會想:這裡會不會有一些隱藏的函式實現?於是你需要跳轉到其方法實現中去查詢。但是在實際開發中,大部分的 property 其實是使用編譯器自動生成的 getter 和 setter 方法,於是你會找不到實現,這個時候,你才知道:「哦,原來這段**並沒有做自定義的成員初使化工作」。
這種預設的隱藏在**中多了,會影響**的閱讀和維護。其實大部分的類成員變數都需要在類初使化方法中賦值,大部分的 uiviewcontroller 的成員變數,都需要在 viewdidload 方法中賦值。那既然這樣,不如直接在相應的方法中用乙個名為 setupproperty 方法直接進行初使化。這樣的好處是,**的可讀性更好了,self.property 只有需要延遲初使化的情況下才被使用。
簡短的**更易讀
_property 的寫法比 self.property 更短,也更簡單。我認為這樣寫出來的**更方便閱讀。
執行速度更快,ipa體積更小
我之前從來沒想到過這兩者之間的速度和應用體積會有很大差別。不過乙個同行(來自國外著名的社交網路公司)告訴我,他們公司發現二者還是有不小的差距,如果你們的應用需要做一些深度優化,可以考慮一下把 self.property 換成 _property。但我覺得,大部分應用都應該是不需要做這種深度優化的。
kvo 和 kvc
是的,如果用 _property 這種寫法,就不能使用 kvo 和 kvc 了。但是我得反問一下,在乙個類的內部,kvo 自己的私有成員變數算是乙個好設計嗎?我們講類要」高內聚,低耦合」,kvo 是為了實現觀察者模式,讓物件之間相互解耦的。如果把 kvo 用在類的內部,kvo 自己的私有成員,我認為其實這不是乙個很好的設計。
computed properties
是的,在類的內部如果直接使用 _property 形式,也無法使用 computed properties 了,但我認為這影響不大。其實 computed properties 也就是一層對資料訪問的封裝,我們另外實現兩個函式,分別對應資料的 setter 和 getter 功能,就可以達到同樣的效果。
寫在最後
其實我上面提到的這些問題都是小問題,影響不大。但是**風格的統一卻是大問題。所以不管你們專案中使用的是 self.property 風格還是 _property 風格,問題都不大,但是如果你們同時使用這兩種風格,那麼就非常不好了。
希望我的這篇文章能讓大家了解到在這方面的爭論,也希望大家能夠在這一點上,在公司內部達成統一。
類中的靜態類成員變數
myobj.h pragma once include using namespace std class cmyobj cmyobj account.h ifndef account h define account h include class cmyobj class account acc...
iOS 類成員變數和區域性變數的問題
成員變數定義問題 property是為了提供給外部訪問的,省去了get與set方法。如果你宣告了property,而沒有在inte ce宣告變數,那麼自動生成乙個和property一樣的變數名,預設的。在4.0之後可以乎約宣告。個人覺得 public和 protected並沒有很明確的區別,在他們作...
類中的靜態成員變數 靜態成員函式
類中的靜態成員變數 靜態成員函式?1 類中的靜態成員變數 靜態成員變數屬於整個類,不屬於某個特定的物件,因此無論建立了多少個物件,所有物件都共享類中的靜態成員變數。靜態成員變數必須在類內宣告,類外初始化。2 類中的靜態成員函式 靜態成員函式也是屬於類本身,而不屬於某個特定的物件。靜態成員函式與普通成...