在開發過程中我們需要一些全局對象來將程序的各個部分連接起來,這些全局對象中最重要的就是UIApplication對象。但在實際編程中我們並不直接和UIApplication對象打交道,而是和其代理打交道。
UIApplication 是iPhone應用程序的開始並且負責初始化並顯示UIWindow,並負責加載應用程序的第一個UIView到UIWindow窗體中。 UIApplication的另一個任務是幫助管理應用程序的生命周期,而UIApplication通過一個名字為 UIApplicationDelegate的代理類來履行這個任務。盡管UIApplication會負責接收事件,而 UIApplicationDelegate則決定應用程序如何去響應這些事件,UIApplicationDelegate可以處理的事件包括應用程序 的生命周期事件(比如程序啟動和關閉)、系統事件(比如來電、記事項警告),本文會介紹如何加載應用程序的UIView到UIWindow以及如何利用 UIApplicationDelegate處理系統事件。
通常對於UIApplication讀者是沒必要修改它的,只需要知道UIApplication接收系統事件即可,而如何編寫代碼來處理這些系統事件則是 程序員的工作。處理系統事件需要編寫一個繼承自UIApplicationDelegate接口的類,而UIApplicationDelegate接口 提供生命周期函數來處理應用程序以及應用程序的系統事件。
如果利用Xcode的模板創建項目,Xcode會為程序員創建繼承自UIApplicationDelegate的類,但不會自動實現繼承自 UIApplicationDelegate的可選的事件處理函數。如果讀者創建一個名為“TestUIApplication”的項目,Xcode會自 動創建TestUIApplicationAppDelegate.h和TestUIApplicationAppDelegate.m文件,文件的聲明 如下:
@interface TestUIApplicationAppDelegate : NSObject <UIApplicationDelegate>
而應用程序的UIApplication則被定義在MainWindow.xib文件中,並且有一個作為outlet的UIApplicationDelegate引用。
iPhone 並不是多任務的操作系統,所以應用程序很容易受到打擾,比如一個來電可能導致應用程序失去焦點,如果這個時候接聽了電話,那么應用程序會自動終止運行。還 有很多其它類似的事件會導致iPhone應用程序失去焦點,在應用程序失去焦點前會調用委托類的 applicationWillResignActive()方法,而應用程序再次獲取到焦點的時候會調用 applicationDidBecomeActive()方法。比如在運行應用程序的時候鎖屏會調用委托類的 applicationWillResignActive()方法,而當屏幕被解鎖的時候,又會調用 applicationDidBecomeActive()方法。
另 外一個非常重要的方法就是applicationDidReceiveMemoryWarning(),因為iPhone設備只有有限的內存,如果為應用 程序分配了太多內存操作系統會終止應用程序的運行,但在終止之前操作系統會通過先調用委托類的 applicationDidReceiveMemoryWarning()方法警告應用程序,在UIApplication接收到這個事件后它會傳遞給 委托類的applicationDidReceiveMemoryWarning()方法,委托類在這個方法內可以進行釋放內存的操作以防止操作系統強制 終止應用程序的運行。
現在來看協議中定義的這些需要實現的方法分別是什么作用:
1、- (void)applicationWillResignActive:(UIApplication *)application
說明:當應用程序將要入非活動狀態執行,在此期間,應用程序不接收消息或事件,比如來電話了
2、- (void)applicationDidBecomeActive:(UIApplication *)application
說明:當應用程序入活動狀態執行,這個剛好跟上面那個方法相反
3、- (void)applicationDidEnterBackground:(UIApplication *)application
說明:當程序被推送到后台的時候調用。所以要設置后台繼續運行,則在這個函數里面設置即可
4、- (void)applicationWillEnterForeground:(UIApplication *)application
說明:當程序從后台將要重新回到前台時候調用,這個剛好跟上面的那個方法相反。
5、- (void)applicationWillTerminate:(UIApplication *)application
說明:當程序將要退出是被調用,通常是用來保存數據和一些退出前的清理工作。這個需要要設置UIApplicationExitsOnSuspend的鍵值。
6、- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
說明:iPhone設備只有有限的內存,如果為應用程序分配了太多內存操作系統會終止應用程序的運行,在終止前會執行這個方法,通常可以在這里進行內存清理工作防止程序被終止
7、- (void)applicationSignificantTimeChange:(UIApplication*)application
說明:當系統時間發生改變時執行
8、- (void)applicationDidFinishLaunching:(UIApplication*)application
說明:當程序載入后執行
9、- (void)application:(UIApplication)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame
說明:當StatusBar框將要變化時執行
10、- (void)application:(UIApplication*)application willChangeStatusBarOrientation:
(UIInterfaceOrientation)newStatusBarOrientation
duration:(NSTimeInterval)duration
說明:當StatusBar框方向將要變化時執行
11、- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url
說明:當通過url執行
12、- (void)application:(UIApplication*)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation
說明:當StatusBar框方向變化完成后執行
13、- (void)application:(UIApplication*)application didChangeSetStatusBarFrame:(CGRect)oldStatusBarFrame
說明:當StatusBar框變化完成后執行
做iPhone開發首先第一件就是得知道iPhone程序的生命周期,說白點就是當點擊程序圖標啟動程序開始到退出程序整個使用運行過程中底下的代 碼都發生了什么,只有理解了這個才能游刃有余的掌握iPhone程序的開發,否則在寫程序的時候有點渾渾僵僵不知所以然的感覺。首先忘記Xcode給我們 生成的代碼模板,忘記xib忘記ib,我們親自一行一行來寫一個Hello World程序,雖然真正開發項目的時候並不需要這樣做Xcode模板和ib都會為我們做好這些打雜的事情,但是現在完全由我們自己來寫,放心這個程序是 個非常的簡單的Hello World 程序,代碼也很少總共加起來不過10幾行。
在這之前我們先來看看Objective-C語言的關於這段協議代碼:
- @protocol SimpleProtocol
- -(void)doSomething:(NSString *)str;
- @end
- @interface SimpleClass:NSObject< SimpleProtocol >{
- }
- @end
- @implementation SimpleClass
- -(void) doSomething:(NSString *)str{
- NSLog(str);
- }
- @end
這樣是一個簡單的協議示例,類SimpleClasss實現了名為SimpleProtocol的協議。協議在其它語言里跟接口非常類似,記住這個協議的實現,接下來會有用的。
接下來用Xcode新建一個名為HelloWorld的Window-based Application類型的項目。大體上講一下項目的文件結構,由Xcode模板生成的項目主要包含Classes(Hello World Appdelegate.h和Hello World Appdelegate.m)、Other Sources(main.m和Hello World_Prefix.pch)、Resources(Main Window.xib和Hello World-info.plist)、Frameworks(iPhone SDK提供的系統框架)、Products(Hello World.app)這幾部分。直接運行這個工程會在模擬器里看到一個白色的顯示界面程序,由此可見沒寫一行代碼Xcode已經給我們生成了一個很簡單的 項目模板。
每一個iPhone程序都包含一個UIApplication對象,它管理整個程序的生命周期,從加載第一個顯示界面開始,並且監聽系統事件、程序 事件調度整個程序的執行。那么上面這個簡單項目中的UI Application對象在哪呢?在這個項目中我們找不到任何關於UI Application的代碼,其實在項目中UI Application對象是由UI Application Main方法初始化到內存中,首先打開Other Sources文件夾下的main.m源文件,里面只包括了一個main方法,和所有的C程序一樣這個是程序入口。代碼如下:
- int main(int argc, char *argv[]) {
- NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
- int retVal = UIApplicationMain(argc, argv, nil, nil);
- [pool release];
- return retVal;
- }
在main函數中第二行代碼UI Application Main(argc, argv, nil, nil);對UIApplication對象進行了初始化,這個方法除了argc 和 argv 參數外,另外這個函數還有2個兩個字符串參數來識別UI Application類和UI Application代理類,在這里默認是2個nil,第一個參數為nil就默認把UI Application類作為缺省值進行初始化,可以在這里不填nil而是使用自己定義的UI Application子類。至於第二個參數nil就設置為nil就把模板生成的Hello World Appdelegate類作為默認值。這里有了UI Application對象怎么又出來一個UI Application代理類對象呢?這里需要說明UI Application對象說是管理整個程序的生命周期其實它是什么具體的事情都不干,它只負責監聽事件當需要做實際工作的時候就交給UI Application代理類去做,UI Application相當於傳令官負責只把命令傳達給UI Application代理類這個士兵,然后由這個士兵真正去沖鋒陷陣,所以需要給UI Application對象設置代理類。
非常不好意思寫了一堆羅嗦的文字還沒有進入正題,不過這些羅嗦還是非常有必要的,現在開始編寫我們的第一個iPhone程序helloWorld。 上面不是說了要忘記代碼模板,忘記xib忘記Interfcae Builder嘛,這樣我們把模板自動生成的部分刪除了,找到Other Sources文件下main.m刪除,找到Classes文件夾下的Hello World Appdelegate.h和Hello World Appdelegate.m刪除,把Resources文件夾下的Main Window.xib刪除,還有一件事情一定要做那就是打開Resources文件夾下Hello World-info.plist,然后找到key為“Main nib file base name”刪除因為在上面我們已經刪除了Main Window.xib,這樣就完成的工程的清理,變成了一個真正的空的工程沒有什么實現代碼。
完成上面的清理工作后,接下來開着我們的編寫,首先新建程序入口main.m文件已經main方法,程序從這里開始!代碼如下:
- int main(int argc, char *argv[]) {
- NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
- int retVal = UIApplicationMain(argc, argv, nil, @”SampleDelegate”);
- [pool release];
- return retVal;
- }
NSAutoreleasePool內存自動釋放池這個干什么我就不說了,你懂得的。這里主要看一下第二行UI Application Main(argc, argv, nil, nil);與模板生成的相比改成UI Application Main(argc, argv, nil, @”SampleDelegate”);這樣做我們為UI Application對象設置了名為SampleDelegate代理類,上面不是說了UI Application是不處理具體事情的,真正做事的是UI Application代理類,這個名為SampleDelegate代理類就是我們需要具體寫代碼實現的,當UI Application初始化后就開始監聽事件,根據不同的監聽事件讓SampleDelegate代理類做不同的處理,比如顯示第一個顯示界面。
新建名為SampleDelegate.m的類,在SampleDelegate.h輸入如下代碼:
- @interface SampleDelegate : NSObject<UIApplicationDelegate> {
- }
- @end
注意到沒有,SampleDelegate: NSObject <UIApplicationDelegate>這個寫法是不是很眼熟 ,在看看最上面那段Objective-C語言的關於協議代碼,SimpleClass類需要實現SimpleProtocol協議定義的方法,這樣看來 UIApplicationDelegate是一個協議定義,同樣SampleDelegate也需要實現UI Application Delegate中定義的方法,只是這個協議是系統定義好的(具體可以參看UI Application Delegate.h)而SimpleProtocol是我們自己定義的,但是要做的事情相同,就是SampleDelegate需要去實現這UI Application Delegate協議定義好的方法, 這些方法就是UI Application對象監聽到系統變化的時候通知UI Application對象代理類SampleDelegate執行的相應方法。下面是SampleDelegate的實現代碼寫在 SampleDelegate.m中注意到沒有,SampleDelegate: NSObject <UIApplicationDelegate>這個寫法是不是很眼熟 ,在看看最上面那段Objective-C語言的關於協議代碼,SimpleClass類需要實現SimpleProtocol協議定義的方法,這樣看來 UI Application Delegate是一個協議定義,同樣SampleDelegate也需要實現UI Application Delegate中定義的方法,只是這個協議是系統定義好的(具體可以參看UI Application Delegate.h)而SimpleProtocol是我們自己定義的,但是要做的事情相同,就是SampleDelegate需要去實現這UI Application Delegate協議定義好的方法, 這些方法就是UI Application對象監聽到系統變化的時候通知UI Application對象代理類SampleDelegate執行的相應方法。下面是SampleDelegate的實現代碼寫在 SampleDelegate.m中:
- @implementation SampleDelegate
- - (void)applicationWillResignActive:(UIApplication *)application{}
- - (void)applicationDidBecomeActive:(UIApplication *)application{}
- - (void)applicationDidEnterBackground:(UIApplication *)application{}
- - (void)applicationWillEnterForeground:(UIApplication *)application{}
- - (void)applicationWillTerminate:(UIApplication *)application{}
- - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application{}
- - (void)applicationSignificantTimeChange:(UIApplication*)application{}
- - (void)applicationDidFinishLaunching:(UIApplication*)application{}
- - (void)application:(UIApplication*)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame{}
- - (void)application:(UIApplication*)application willChangeStatusBarOrientation:(UIInterfaceOrientation)newStatusBarOrientation duration:(NSTimeInterval)duration{}
- - (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url{
- return YES;
- }
- - (void)application:(UIApplication*)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation{}
- - (void)application:(UIApplication*)application didChangeSetStatusBarFrame:(CGRect)oldStatusBarFrame{}
- @end
現在來看協議中定義的這些需要實現的方法分別是什么作用:
◆- (void)applicationWillResignActive:(UIApplication *)application
說明:當應用程序將要入非活動狀態執行,在此期間,應用程序不接收消息或事件,比如來電話了
◆- (void)applicationDidBecomeActive:(UIApplication *)application
說明:當應用程序入活動狀態執行,這個剛好跟上面那個方法相反
◆- (void)applicationDidEnterBackground:(UIApplication *)application
說明:當程序被推送到后台的時候調用。所以要設置后台繼續運行,則在這個函數里面設置即可
◆- (void)applicationWillEnterForeground:(UIApplication *)application
說明:當程序從后台將要重新回到前台時候調用,這個剛好跟上面的那個方法相反。
◆- (void)applicationWillTerminate:(UIApplication *)application
說明:當程序將要退出是被調用,通常是用來保存數據和一些退出前的清理工作。這個需要要設置UIApplicationExitsOnSuspend的鍵值。
◆- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
說明:iPhone設備只有有限的內存,如果為應用程序分配了太多內存操作系統會終止應用程序的運行,在終止前會執行這個方法,通常可以在這里進行內存清理工作防止程序被終止
◆- (void)applicationSignificantTimeChange:(UIApplication*)application
說明:當系統時間發生改變時執行
◆- (void)applicationDidFinishLaunching:(UIApplication*)application
說明:當程序載入后執行
◆- (void)application:(UIApplication)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame
說明:當StatusBar框將要變化時執行
◆- (void)application:(UIApplication*)application willChangeStatusBarOrientation:
- (UIInterfaceOrientation)newStatusBarOrientation
- duration:(NSTimeInterval)duration
說明:當StatusBar框方向將要變化時執行
◆- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url
說明:當通過url執行
◆- (void)application:(UIApplication*)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation
說明:當StatusBar框方向變化完成后執行
◆- (void)application:(UIApplication*)application didChangeSetStatusBarFrame:(CGRect)oldStatusBarFrame
說明:當StatusBar框變化完成后執行
下圖是我總結的一個大概流程圖,不是很准確但是基本上也說明了整個過程,僅供參考。
到這為止我們的這個程序運行起來還是什么都沒有看到,確實我們也沒有寫具體的功能代碼,接下來我們要做的就是在屏幕上顯示“Hello World!”,首先知道一下要在屏幕上顯示,首先需要一個UIWindow對象,這個你可以認為是一個電視機,然后還需要往這個UIWindow對象里 添加UIView對象, UIView相當於電視上一幕一幕的畫面。通過上面的流程知道要在程序后顯示可以在applicationDidFinishLaunching方法中處 理,這樣修改applicationDidFinishLaunching方法如下:
- - (void)applicationDidFinishLaunching:(UIApplication*)application{
- UIWindow *window=[[UIWindow alloc]initWithFrame:[[UIScreen mainScreen] bounds]];
- SampleViewController *viewctrl=[[SampleViewController alloc]init];
- [window addSubview:viewctrl.view];
- [window makeKeyAndVisible];
- }
上面的代碼中做了如下幾件事情:
◆實例化了一個UIWindow對象
◆實例化了SampleViewController對象
◆把SampleViewController對象UIView對象添加到UIWindow對象中
◆顯示UIWindow對象
看這段代碼我們並沒有直接實例化一個UIView對象然后添加給UIWindow對象而且通過SampleViewController對象,它是 UIViewController子類負責視圖的顯示控制,非常的好用,在這里我們只是實現了loadView就夠了,我們只要簡單的顯示一下 “Hello World!”文字, 具體代碼如下:
- @interface SampleViewController : UIViewController {}
- @end
- @implementation SampleViewController
- -(void)loadView{
- UIView *contentView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
- contentView.backgroundColor = [UIColor blackColor];
- self.view = contentView;
- [contentView release];
- CGRect labelFrame = CGRectMake(40.0f, 200.0f, 240.0f, 60.0f);
- UILabel *frontLabel = [[UILabel alloc] initWithFrame:labelFrame];
- frontLabel.text = @"Hello World!";
- frontLabel.font = [UIFont fontWithName:@"Georgia" size:24.0f];
- frontLabel.textColor = [UIColor colorWithRed:0.82f green:1.0f blue:0.286f alpha:1.0f];
- frontLabel.backgroundColor = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.0f];
- [contentView addSubview:frontLabel];
- [frontLabel release];
- }
- @end
到這里我們已經完成的Hello World程序的編寫,點擊運行就能看到如下的效果圖:
