不要在init的方法中訪問self.view
使用data source protocols(資料來源協議)來明顯地將data從view上區分開來
使用已經存在的navigationitem對象
在標頭檔中僅暴露公有屬性和方法
使用lldb來進行測試
使用NSZombieEnabled來發現記憶體泄露
-----------------------------------------------------------------------------------------------------------------------
時刻銘記著views的生命週期
不斷地提醒自己,在任何時候,你的view都可能被銷毀
(1) 不要在init的方法中訪問self.view
你永遠不應該在你的controller的init方法中訪問self.view。這麼做總是會導致很多難於調試的bug,因為在收到一個記憶體警告之後init的邏輯將無法再次執行一遍。
考慮下面這個簡單的例子:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) { self.view.backgroundColor = [UIColor underPageBackgroundColor]; } return self;}
想象一下這個controller是一個navigation stack(註:iOS中使用棧的結構來管理那些navigationController相關的視圖對象)的根對象,與此同時一個記憶體警告發生了(收到記憶體警告如果沒有正確處理,iOS系統會銷毀一些視圖以釋放記憶體空間)。當我們返回到該控制器的時候,該視圖將不再以underPageBackgroundColor作為其背景色。這會給調試帶來麻煩,即便是對於那些有經驗的iOS工程師也是如此。
(2) 使用data source protocols(資料來源協議)來明顯地將資料從視圖上區分開來
當你正在設計一個視圖來與資料集進行互動的時候,你總是應該通過一個data source protocol來擷取資料,而不是通過暴露訪問器(setter)的形式。視圖不是資料的容器,所以不應該讓它們承受這樣的“罪責”。正確的做法是,視圖應該被當做一個“失去存在感”的可擴充的組件,在任何時候都是。
作為一個一般性的通用法則,在視圖上的任何超出靜態展現的資訊都應該通過data source或者delegate來擷取。
UILabel就是一個不需要datasource的視圖,它是個很好的樣本。它所有的屬性通常都被設定一次,並且通常在視圖的生命週期內都不期待被改變。
而從另一方面來說,UITableView是一個需要data source來提取資料的好例子。讓我們想象一下當我們使用UITableView的時候不是通過一個datasource而是僅僅通過提供setter的情況將會是什麼樣子。
如果真是這樣設計的話,當開發人員企圖使用table view對象來儲存他們的資料的時候,將會導致不可避免的濫用。當收到記憶體警告,table view 不可避免地被釋放時,資料也將一同消失(因為它通過setter儲存在tableview對象內部)。這意味著我們需要儲存的資料能夠在任何情況下北table view的多個執行個體在其生命週期內可以訪問。
UIViewController
view controller用來完成model與view之間的綁定
(1)使用已存在的navigation item對象
每一個UIViewController的執行個體都有一個navigationItem屬性,它應該被用來指定左/右導覽按鈕以及標題視圖。你不應該建立一個UINavigationItem 對象,因為在你訪問self.navigationItem的時候UIViewController的基類實現將自動幫你建立一個。簡單地使用self.navigationItem來訪問並為其設定屬性:
// UIViewController will automatically create the navigationItem object.self.navigationItem.rightBarButtonItem = doneButton;
NSObject
(1) 在標頭檔中僅暴露公有屬性和方法
obj-c允許你在一個category interface(.m檔案中)定義私人的屬性。利用這個特性提供更好地訪問限制吧。
這等價於通過@provate進行定義,並且能夠帶來一些額外的好處——對於代碼的修改不需要重新編譯並且不影響其他對象的內部結構。在一個大型項目中,這是大有裨益的。
樣本:
ViewController.h
@interface ViewController : UIViewController@property (nonatomic, readonly, assign) NSInteger objectId;@end
ViewController.m
#import "ViewController.h"@interface ViewController()@property (nonatomic, readwrite, assign) NSInteger objectId;// Notice that this property doesn't need to be in the .h. Objective-C will create this// property on the fly!@property (nonatomic, readwrite, retain) UILabel* objectLabel;@end@implementation ViewController@synthesize objectId;@synthesize objectLabel;...@end
Debugging
(1)使用lldb來進行測試
lldb允許你檢查類的屬性,不需要在對象的執行個體上有明確地定義
(2)使用NSZombieEnabled來發現記憶體泄露
當NSZombieEnabled被使用,那些從記憶體中被釋放的對象都將被儲存為“zombies”。如果在未來的某個時間你企圖再次訪問這些已被釋放的對象。這對於你去判斷在什麼地方發生記憶體泄露將會大有協助。
(註:關於這兩個debug的配置,請自行google)