文章出處

首先要確定一點,我們的App,要基于XIB文件進行編程,而不是在每個相應的ViewController里面去手動創建頁面的每個控件。這樣做的好處是,將頁面布局與業務邏輯徹底隔離。于是我們可以把xib的繪制工作交給美工人員,而iOS程序員,主要關心的是業務邏輯。

有人會懷疑過多的xib會導致App體積變大,我曾經有專門看過ipa文件解壓后的文件列表,我發現每個xib也就2k大小,而一個App最多也就七八十個xib,那么就是說共計150k大小的樣子,由于是xml文本文件,所以壓縮后更小。而相比較下,占用App體積最多的,往往是開機畫面圖,引導圖這些東西,如果真的想要App瘦身,應該在圖片上進行優化,而不是不使用xib直接布局。

另一個需要明確的是,在一開始創建ViewController的時候,不要同時創建xib文件,因為這樣子的話,就在xib中把ViewController和xib進行關聯了,而我們要做的是解耦,這顯然不合理。所以正確的流程是,分開創建ViewController和xib,不要進行管理。在ViewController的初始化中,加載xib文件,如下所示:

接下來要做的事情,有時候連我都覺得匪夷所思。我們先來看一段代碼:

 1 #import "APageViewController.h"
 2 
 3 @interface APageViewController ()
 4 
 5 @end
 6 
 7 @implementation APageViewController
 8 
 9 - (void)loadView
10 {
11     [super loadView];
12     // Do any additional setup after loading the view.
13 
14     //1.從xib中獲取View
15     NSArray* list = [[NSBundle mainBundle] loadNibNamed: @"APageView" owner: self options: nil];
16     self.view = list.lastObject;
17     
18     UILabel* nameLabel = (UILabel*)[self.view viewWithTag: 100];
19     nameLabel.text = @"";
20     
21     UILabel* ageLabel = (UILabel*)[self.view viewWithTag: 200];
22     ageLabel.text = @"";
23     
24     UIButton* getInfoButton = (UIButton*)[self.view viewWithTag: 300];
25     [getInfoButton addTarget: self action: @selector(getInfo) forControlEvents:UIControlEventTouchUpInside];
26     
27     UIButton* clearInfoButton = (UIButton*)[self.view viewWithTag: 400];
28     [clearInfoButton addTarget: self action: @selector(clearInfo) forControlEvents:UIControlEventTouchUpInside];
29 }
30 
31 - (void) getInfo {
32     UILabel* nameLabel = (UILabel*)[self.view viewWithTag: 100];
33     nameLabel.text = @"包小強";
34     
35     UILabel* ageLabel = (UILabel*)[self.view viewWithTag: 200];
36     ageLabel.text = @"31.6";
37 }
38 
39 - (void) clearInfo {
40     UILabel* nameLabel = (UILabel*)[self.view viewWithTag: 100];
41     nameLabel.text = @"";
42     
43     UILabel* ageLabel = (UILabel*)[self.view viewWithTag: 200];
44     ageLabel.text = @"";
45 }
46 
47 - (void)dealloc {
48     [super dealloc];
49 }
50 
51 @end

 上面的代碼,是再普通不過的一段代碼,讀取一個xib,獲取到View的句柄,初始化其中的每個控件,為按鈕掛上點擊后的方法事件,使得按鈕變紅。內部還有個計數器變量,每次點擊按鈕都會加1。巧的是,恰好還要偵聽一個通知(Notification)。最后,調用API。

我們發現,有2個問題:

1)在willDidLoad中做了太多的事情,又是初始化變量,又是初始化控件,又是給按鈕掛事件,注冊通知,還要調用API。

2)每次使用控件時,都要根據在xib中指定的tag重新獲取,而iOS中的控件tag值,只能是整數。

我們的解決方案是,既然頁面每次加載都會調用loadViewviewDidLoad方法,每次銷毀都會調用dealloc方法,那么干脆就在基類BaseViewController重寫了這幾個方法,于是現在頁面的生命周期如下所示:

201309051002.jpg

相應的基類代碼請參見本章的源碼。

 

我們在每個頁面都會重寫createFieldsloadData這些方法,每個方法的意義如下:

1createFieldsdestroyFields: 創建/銷毀頁面級變量的地方。

2createViewsdestroyViews: 創建/銷毀頁面內控件的地方。

3createEventsdestroyEvents: 創建/銷毀頁面內事件、通知的地方。

4loadData: 如果頁面加載過程需要調用MobileAPI,則寫在這個地方。

 

我們在程序里把代碼分門別類寫在各自的地方,易于管理(避免了經常會聲明了變量而忘記銷毀的問題)。

 

于是剛才的代碼文件,我們將其重構為: 

 1 #import "APageViewController.h"
 2 
 3 @interface APageViewController () {
 4     UILabel* nameLabel;
 5     UILabel* ageLabel;
 6     UIButton* getInfoButton;
 7     UIButton* clearInfoButton;
 8 }
 9 
10 @end
11 
12 @implementation APageViewController
13 
14 - (void)createFields {
15 
16 }
17 
18 - (void)destroyFields {
19     
20 }
21 
22 - (void)createViews {
23     //1.從xib中獲取View
24     NSArray* list = [[NSBundle mainBundle] loadNibNamed: @"APageView" owner: self options: nil];
25     self.view = list.lastObject;
26     
27     nameLabel = (UILabel*)[self.view viewWithTag: 100];
28     nameLabel.text = @"";
29     
30     ageLabel = (UILabel*)[self.view viewWithTag: 200];
31     ageLabel.text = @"";
32     
33     getInfoButton = (UIButton*)[self.view viewWithTag: 300];    
34     clearInfoButton = (UIButton*)[self.view viewWithTag: 400];
35 }
36 
37 - (void)destroyViews {
38     
39 }
40 
41 - (void)createEvents {
42     [getInfoButton addTarget: self action: @selector(getInfo) forControlEvents:UIControlEventTouchUpInside];
43     [clearInfoButton addTarget: self action: @selector(clearInfo) forControlEvents:UIControlEventTouchUpInside];
44     
45 }
46 
47 - (void)destroyEvents {
48     
49 }
50 
51 - (void)loadData {
52     //在這里調用API,對于多個API的調用,參加后續章節
53 }
54 
55 - (void) getInfo {
56     nameLabel.text = @"包小強";
57     ageLabel.text = @"31.6";
58 }
59 
60 - (void) clearInfo {
61     nameLabel.text = @"";
62     ageLabel.text = @"";
63 }
64 
65 @end

 

以上的代碼重構,要遵守幾個規則:

1)在createFields方法中接收從上一個頁面傳遞過來的參數

2)在createFields方法中初始化變量

3)將要操作的控件,都在ViewController中作為類級別的變量來聲明

3)在createViews方法中,加載xib文件,并通過Tag給控件一次性賦值

4)在createEvent方法中,為控件掛上事件方法,比如按鈕的點擊

5)如果有NotificationCenter,統一在createEvent方法中addObserver,在destroyEvent方法中removeObserver。

6)在DestroyFields方法中,釋放/銷毀所有引用型變量。

7)在DestroyViews方法中,釋放/銷毀所有控件。

 

所有的ViewController都這么寫,整個App整齊劃一。尤其是將一個頁面的所有控件一次性都從xib中根據tag值取出來,雖然浪費了一些內存,但是可以隨時隨地直接使用。

將聲明一個按鈕和為按鈕添加一個點擊事件方案分開在2個方法內寫,一開始你會非常不習慣,但是當控件多了、事件多了的時候,是一目了然的。記住,我們在做的是企業級App開發,而不是小型App。

 

看到最后,熟悉網站端編程的人笑了,沒錯,這種新的生命周期,就是從javascript中借鑒來的。js是一門弱語言,所以需要自定義生命周期并按部就班在不同的方法中寫不同的方法,生命周期的重新定義,或者說是擴展,只是js代碼框架中的一個小部分。

 

本章代碼下載:

YoungHeart-Chapter-04-1.zip (重構前)

YoungHeart-Chapter-04-2.zip   (重構后)

 


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()