iOS 開發中的爭議(一),ios開發中爭議

來源:互聯網
上載者:User

iOS 開發中的爭議(一),ios開發中爭議
序言

打算分享一些有爭議的話題,並且表達一下我的看法。這是該系列的第一篇,我想討論的是:類的成員變數應該如何定義?

在 Objective-C 的語言的早期,類的私人成員變數是只能定義在 .h 的標頭檔裡面的。像如下這樣:

@interface ViewController : UIViewController {    @private    NSInteger _value;}

之後,蘋果改進了 Objective-C,允許在 .m 裡面添加一個當前類的擴充,即沒有名字的 Category,來實現增加類的成員變數。像如下這樣:

@interface ViewController ()@property (nonatomic) NSInteger value;@end

這樣的好處是,這些變數在標頭檔中被徹底隱藏起來了,不用暴露給使用者。

接著,在 2013 年的 WWDC 中,蘋果進一步改進了 Objective-C,允許在 .m 的
@implementation 中直接添加類的私人成員變數。像如下這樣:

@implementation ViewController {    NSInteger _value;}

於是,大家對於如何定義私人的成員變數上就產生的分歧。許多人喜歡用匿名的 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只有需要延遲初使化的情況下才被使用。

關於這個還有一個小故事,我之前 Review 過一個同事的 iOS 端代碼,那個同事喜歡把 table view 的資料另外封裝成一個類,而我覺得這些資料其實就是一個數組,沒必要進行這一層封裝,最終我們爭論了比較久。我的觀點是,一切隱藏都是對代碼複雜性的增加,除非它帶來了好處,例如達到了代碼複用,提高了代碼的可維護性等,否則,沒有好處的封裝只會給代碼閱讀理解帶來成本。就我現在的經曆中,大部分的 table view 的資料都可以放在一個數組中,沒必要把這個數組封裝起來,另外提供一套操作這個數組資料的方法。

簡短的代碼更易讀

_property 的寫法比 self.property 更短,也更簡單。我認為這樣寫出來的代碼更方便閱讀。

執行速度更快,IPA體積更小

我之前從來沒想到過這兩者之間的速度和應用體積會有很大差別。不過一個同行(來自國外著名的社交網路公司)告訴我,他們公司發現二者還是有不小的差距,如果你們的應用需要做一些深度最佳化,可以考慮一下把self.property 換成 _property。但我覺得,大部分應用都應該是不需要做這種深度最佳化的。

KVO 和 KVC

是的,如果用 _property 這種寫法,就不能使用 KVO 和 KVC 了。但是我得反問一下,在一個類的內部,KVO 自己的私人成員變數算是一個好設計嗎?我們講類要”高內聚,低耦合”,KVO 是為了實現觀察者模式,讓對象之間相互解耦的。如果把 KVO 用在類的內部,KVO 自己的私人成員,我認為其實這不是一個很好的設計。

Computed Properties

在 Swift 中,引入了 Computed Properties 的概念,其實這在 Objective-C 中也有,只是沒有專門給它名字。如果一個 property 我們提供了對應的 setter 和 getter,並且沒有直接使用其對應的 _property 變數,那麼這個 property 就是所謂的 Computed Properties。

是的,在類的內部如果直接使用 _property 形式,也無法使用 Computed Properties 了,但我認為這影響不大。其實 Computed Properties 也就是一層對資料存取的封裝,我們另外實現兩個函數,分別對應資料的 setter 和getter 功能,就可以達到同樣的效果。

循環參考問題

直接用私人變數有個需要特別注意的地方,在 block 裡直接寫 _property 相當於 self->_property,雖然沒寫 self,但是暗含了對 self 的retain,容易造成循環參考。要記得用 weakSelf/strongSelf 大法,這一點確實是被很多人忽視的

寫在最後

其實我上面提到的這些問題都是小問題,影響不大。但是代碼風格的統一卻是大問題。所以不管你們項目中使用的是self.property 風格還是 _property 風格,問題都不大,但是如果你們同時使用這兩種風格,那麼就非常不好了。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.