天天看點

[轉]iPhone開發指南-應用程式核心

http://soft-app.iteye.com/blog/927325

iPhone開發指南-應用程式核心

應用程式核心

每個iPhone應用程式都基于UIKit架構而建構,是以擁有同樣的核心架構。UIKit提供運作應用程式的關鍵對象并且協調使用者輸入處理和螢幕内容顯示。應用程式彼此之間區分開來的地方在于如何配置這些預設對象和它們如何把自定義對象整合到它們的應用程式使用者界面和行為中。

盡管定制你的應用程式使用者界面和基本行為發生在你的自定義代碼中,仍然有很多定制必須使用在應用程式的最高層。因為這些應用層的定制影響了你的應用程式和系統以及其它安裝程式之間的互動方式,了解什麼時候該采取行動而什麼時候預設行為已經足夠這一點很重要。本章提供了一個核心應用程式架構和進階别定制點方面的總體描述來幫助你做出決定。

核心應用程式架構

從你的程式被使用者啟動,到它退出,UIKit架構管理着大多數應用程式關鍵基礎結構。一個iPhone應用程式不斷從系統中接收事件并必須響應這些事件。接收事件是UIApplication 對象的工作但是響應這些事件是你自定義代碼的責任。為了了解你在哪些地方需要響應事件,其實,這對了解一點整個應用程式生命周期和事件循環也有幫助。下面的章節描述了這些周期并且還提供了一些貫穿iPhone應用程式開發的核心設計模式的總結。

應用程式生命周期

應用程式生命周期構成發生在你的應用程式啟動和退出期間的事件序列。在iPhone 作業系統中, 使用者通過點選桌面上的菜單啟動你的應用程式。在點選發生之後的短時間内,系統顯示一些過渡圖檔并開始通過調用main函數啟動你的應用程式。從這一點開始,一大堆的初始化工作被移交給UIKit,它将加載應用程式的使用者界面并準備好它的事件循環。在事件循環期間,UIKit 協調你自定義對象的事件傳遞和應用程式發出指令的響應。當使用者執行一個動作會讓你的應用程式退出時,UIKit通知你的應用程式并開始這個結束過程。

圖1-1 描繪了一個iPhone應用程式的簡單生命周期。這個圖顯示了應用程式啟動到退出期間發生的事件序列。在初始化和結束階段,UIKit發送特定的消息給應用程式代理對象以便其知道發生了什麼。在事件循環階段,UIKit分發事件給你的應用程式自定義事件處理器。處理初始化和結束事件在“Initialization and Termination,” 中描述,而事件處理過程在“The Event-Handling Cycle” 中介紹,在後面的章節将覆寫更多的細節。

Figure 1-1應用程式生命周期

[轉]iPhone開發指南-應用程式核心

Main函數

在iPhone應用程式裡, main函數功能被最小化了。大部分實際工作是在UIApplicationMain 函數中完成的。 當你在Xcode中開始一個新的應用程式項目時,每個項目模版都提供了一個标準main函數實作如同在 “Handling Critical Application Tasks.”裡的那個。Main函數隻做了三件事: 建立了一個自釋放池(autorelease pool),調用UIApplicationMain,然後釋放autorelease pool。 除了很少的特例,你不應該修改它。

Listing 1-1iPhone應用程式的main函數

#import <UIKit/UIKit.h>
int main(int argc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
return retVal;
}

注意:自釋放池用在記憶體管理中。它是一個Cocoa機制用來延遲在一個函數體内建立的對象的釋放。更多資訊參見Memory Management Programming Guide for Cocoa。對于和自釋放池相關的iPhone應用程式特定的記憶體管理指南,參見“Allocating Memory Wisely.”

上述清單中的中心部分UIApplicationMain函數采用了4個參數并使用它們來初始化應用程式。盡管你沒必要更改傳入參數的預設值,還是值得解釋一下它們起動應用程式時的用途。除了argc 和 argv 參數外,這個函數采用兩個字元串參數來識别基本類(也就是,應用程式對象類)和應用程式代理類。如果這個基本類字元串為空,UIKit使用UIApplication類作為預設值。 如果應用程式代理類為空,UIKit假設它為從你的應用程式主nib檔案加載的對象其中之一(對于使用Xcode模版建立的應用程式)。 設定這些參數任意一個為非空數值将導緻UIApplicationMain 函數在應用程式啟動時建立一個相應類執行個體并為聲明的目的使用它。這樣,如果你的應用程式使用一個自定義的UIApplication子類(不推薦這樣,但是當然是可能的),你将在第三個參數中指定你自定義類的名字。

應用程式代理

監控你的應用程式的高層行為是應用程式代理對象的職責,也就是你提供的自定義對象。代理是用來避免子類化複雜UIKit對象的一個機制,比如預設的UIApplication對象。和使用子類化以及重寫父類方法相反,你無需修改就可以使用這個複雜對象而把自定義的代碼放在代理類中。當感興趣的事件發生時,這個複雜對象發送消息給你的代理對象。你可以使用這些“鈎子”來執行自定義代碼并實作你需要的行為。

重要:這個代理設計模式是用來節約你建立應用程式的時間和精力的。是以了解這個模式很重要。想對iPhone應用程式采用的關鍵設計模式有個總體了解,請參見“Fundamental Design Patterns.” 關于代理和其他UIKit設計模式的更詳細的描述,請參見Cocoa Fundamentals Guide.

應用程式代理對象負責處理一些關鍵的系統消息而且在每個iPhone應用程式中必須存在。這個對象可以是任何你喜歡的類執行個體,隻要它采用了UIApplicationDelegate 協定。 這個協定的方法定義了應用程式生命周期挂載的鈎子,同時也是你實作自定義行為的途徑。盡管你不需要實作所有的方法,每個應用程式代理應該實作在“Handling Critical Application Tasks.”中描述的方法。

關于UIApplicationDelegate協定的另外的資訊,請參見UIApplicationDelegate Protocol Reference。

主Nib檔案

另外一個初始化時期發生的任務是加載應用程式的主nib檔案。如果應用程式資訊property list (Info.plist) 檔案包含了NSMainNibFile關鍵值, 作為初始化過程的一部分,UIApplication 對象加載這個關鍵值指定的nib檔案。主nib檔案是為你自動加載的唯一nib檔案;但是,你可以按照需要加載其他的nib檔案。

Nib 檔案是基于磁盤的資源檔案,儲存了一個或多個對象的一份快照。 一個iPhone應用程式的主nib檔案通常包含一個視窗對象,應用程式代理對象,和可能一個或多個其他管理這個視窗的關鍵對象。加載一個nib檔案重新構成nib檔案中的對象,從它的磁盤表示轉換成一個實際的可以被你的應用程式操作的記憶體版本。從nib檔案中加載的對象和你程式設計式建立的對象沒有差別。不過,對于使用者界面而言,圖形化的建立和使用者界面相關聯的對象并存放在nib檔案中(使用Interface Builder)比程式設計實作要簡便直覺得多。

關于nib檔案以及如何使用的更多資訊,請參見“Nib Files.”。更多關于如何指定你的應用程式主nib檔案的資訊,請參見“The Information Property List.”

事件處理循環

當UIApplicationMain 函數初始化了應用程式之後,它起動必要的基礎元件來管理這個應用程式的事件和繪制循環,這在圖Figure 1-2中描述。當使用者和裝置互動時,iPhone OS 偵測觸摸事件并把它們放到應用程式事件隊列中。UIApplication對象的事件處理元件從事件隊列頂部提取每個事件并遞交給最合适的對象來處理它。比如,一個發生在一個按鈕上的觸摸事件将會被遞交給相應的按鈕對象。事件也可以被遞交給控制器對象(controller objects)和其他不是直接負責處理該觸摸事件的對象。

Figure 1-2事件和繪畫循環

[轉]iPhone開發指南-應用程式核心

在iPhone OS 多點觸摸事件模型中,觸摸資料被包裝在一個簡單的事件對象中(UIEvent)。為了跟蹤單獨的觸摸動作,事件對象中包含了觸摸對象(UITouch),每一個代表一個手指觸摸了螢幕。當這個使用者把手指放在螢幕上,并四處移動它們,最後從螢幕上移開,系統會在相應的觸摸對象中報告每個手指的變化。

當應用程式啟動時,系統為這個應用程式建立一個程序和線程。這個初始線程成為應用程式主線程, UIApplication 對象就在這裡建立主運作循環(main run loop)并配置應用程式的事件處理編碼。圖1-3 顯示了事件處理編碼和主運作循環之間的關系。系統發送的觸摸事件被排隊直到它們能被應用程式的主循環處理。

Figure 1-3在主運作循環中處理事件

[轉]iPhone開發指南-應用程式核心

注意:一個運作循環監控一個給定的執行線程的輸入源。當一個輸入源有資料處理時,這個運作循環喚醒線程并把控制權派發給輸入源處理器。當處理完成時,控制權傳回運作循環,繼續下一個事件或者如果沒有什麼事情做的話就讓這個線程休眠。你可以安裝你自己的輸入源,包括端口和時鐘,在一個運作循環中使用基礎架構中的NSRunLoop 類。更多關于NSRunLoop 以及運作循環的總體描述,請參見Threading Programming Guide.

UIApplication用一個輸入源對象配置主運作循環來處理觸摸事件,把它們分發給合适的響應者對象。一個響應者對象是從UIResponder類繼承而來并且實作了一個或多個處理觸摸事件不同階段的方法。應用程式中的響應者對象包括UIApplication執行個體,UIWindow,UIView,和所有UIView子類。 應用程式通常分發事件給代表應用程式的主視窗的UIWindow 對象。這個視窗對象,依次,轉發這個事件給它的第一響應者first responder,這通常是發生觸摸事件的視圖對象(UIView)。

除了定義處理事件的方法之外,UIResponder類還定義了響應者鍊的程式結構,這是一個協同僚件處理的Cocoa機制。響應者鍊是應用程式中的一個響應者對象連接配接序列,通常從第一響應者開始。如果第一響應者對象不能處理這個事件,它傳遞給響應鍊中的下一個。這個消息繼續回溯響應鍊-給更進階别的響應者對象比如視窗,應用程式,和應用程式代理-直到事件被處理。如果事件最終仍然未被處理,則被抛棄。

處理事件的響應者對象傾向于在移動中設定一系列程式動作而導緻應用程式重畫所有或它的使用者界面的一部分(以及其它可能的輸出,比如播放聲音)。例如,一個控制器對象 (也就是,一個UIControl子類),通過發送一個動作消息給另外一個對象來處理一個事件,通常這個控制器管理着目前激活視圖集。當處理目前消息時,這個控制器可能改變使用者界面或者調整視圖位置,需要部分視圖重新繪制自己。當這個發生時,視圖和繪圖基礎元件接管并以可能的最有效率的方式來處理這些必要的重繪事件。

關于更多事件,響應者以及你如何在自定義對象中處理事件的資訊,請參見“Event Handling.”

關于視窗和視圖如何和事件處理機制融為一體,請參見“The View Interaction Model.”

關于圖形基礎元件以及視圖如何更新的其他資訊,請參見“The View Drawing Cycle.”

基本設計模式

UIKit架構的設計融合了許多Mac OS X上的Cocoa應用程式建立的設計模式。了解這些模式對于建立iPhone應用程式是關鍵的,是以值得花一些時間來了解它們。下面提供了一個這些設計模式的總體描述:

表1-1iPhone應用程式使用的設計模式
設計模式 描述
模型-視圖-控制器(Model-View-Controller) The Model-View-Controller (MVC) 設計模式是一種把你的應用程式劃分為獨立的功能塊的方法。模型(model)部分定義了應用程式底層資料引擎并負責維護資料完整性。視圖(view)部分定義了應用程式的使用者界面并且沒有關于用于顯示的原始資料的明确知識。控制器(controller)部分作為模型和視圖之間的橋梁并負責促進它們彼此之間的更新。
代理(Delegation) 代理(delegation) 設計模型是無需通過子類化就可以修改複雜對象的設計模式,你可以按原樣使用複雜對象然後把任意的自定義修改其行為的代碼放在一個單獨的對象裡面,也就是代理對象。在預定義時期,複雜對象調用代理對象的方法以給它運作自定義代碼的機會。
目标-行為(Target-action) 控件使用目标-行為(target-action)設計模式來把使用者互動通知給你的應用程式。當使用者和控件以預定方式互動時(比如通過觸擊一個按鈕),這個控件發送一個消息(動作)給你指定的對象(目标)。在接收這個動作消息後,目标對象然後可以用一種恰當的方式響應(比如根據按中的按鈕更新應用程式狀态)。
托管記憶體模型(Managed memory model) Objective-C 語言使用一個引用技術機制來決定什麼時候從記憶體中釋放對象。當一個對象第一次建立時,引用計數為1。其它對象可以使用這個對象的retain, release, 或autorelease 方法來恰當的增加和減少計數值。當一個對象引用計數為0時,Objective-C運作時調用對象的清除方法然後釋放它。

關于這些設計模式的更加透徹的讨論,請參見 Cocoa Fundamentals Guide .

繼續閱讀