iOS UIApplication和程序啓動原理

Xcode4.2之前的main函數如下:

int main(int argc, char *argv[])

{

    NSAutoreleasePool *pool = [[NSAutoreleasePool allocinit];

    int retVal = UIApplicationMain(argc, argv, nilnil);

    [pool release];

    return retVal;

}


Xcode4.2工程中的主函數爲

int main(int argc, char *argv[])

{

    @autoreleasepool {

        return UIApplicationMain(argc, argv, nil, NSStringFromClass([TCAppDelegate class]));

    }

}


可以看出一個重要的變化是在4.2使用了ARC技術後,NSAutoreleasePool被廢棄,改用@autoreleasepool,這裏請不要該回原先的方式,如果改變後,在開啓ARC選項後,程序將不能通過編譯。

不論那個版本,UIApplicationMain函數都是程序的關鍵點,下面是對這個函數的分析:

UIApplicationMain()函數是初始化程序的核心,它接受4個參數。


argc和argv:來自於main()接受的兩個參數;


第三個參數:主要類(principal class),必須是UIApplication或其子類的名字,它代表着當前iPhone程序本身,這個程序會去讀info.plist文件獲取配置信息,其中包括主nib文件的值,一般爲MainWindow(.xib);如果該參數爲nil,則默認爲@"UIApplication"


第四個參數:代理類(delegate class),MainWindow.xib文件中遵循UIApplicationDelegate的類的類名,因爲UIApplication定義了一個delegte變量,這個變量應該遵循UIApplicationDelegate,負責控制程序的運行,如果主nib文件沒有這個類,你應該自定義一個這樣的類,並將第四個參數改爲這個類的類名,否則這個程序不知道如何進行運作,因爲前三個參數代表應用程序本身,它除了把應用的事件循環啓動起來,並讀取info.plist裏的配置信息,不做其它任何事情。如果該參數爲nil,則程序假設程序的代理來自Main nib文件。


根據上面的分析,我們來看以下iOS程序的聲明週期


對於UIApplicationMain函數中的第四個參數,我們也可以看出新舊版本的不同,我們建議在原先的工程中使用新的版本,以提高程序的速度,共修改如下幾處

假如你的工程類都是以TC開頭。

1.import你的appdelegate類,並修改第四個參數如下:

UIApplicationMain(argc, argv, nil, NSStringFromClass([TCAppDelegate class]));

2.刪除MainWindow.xib文件

3.在工程的Info.plist文件中刪除下面一行


4.在TCAppDelegate.m文件中,修改

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions函數,如下:


    self.window = [[UIWindow allocinitWithFrame:[[UIScreen mainScreenbounds]];

    // Override point for customization after application launch.

    self.viewController = [[TCViewController allocinitWithNibName:@"TCViewController" bundle:nil];


    self.window.rootViewController = self.viewController;

    [self.window makeKeyAndVisible];

    return YES;

其中加粗部分爲新增部分。

經過上面的修改,我們就可以在程序load的過程中,省去加載MainWindow.xib文件,提高程序的速度。



iPhone應用程序是由主函數main啓動,它負責調用UIApplicationMain函數,該函數的形式如下所示: 
 int UIApplicationMain ( 
 int argc, 
 char *argv[], 
 NSString *principalClassName, 
 NSString *delegateClassName 
 ); 
 那麼UIApplicationMain函數到底做了哪些事情呢?這個函數主要負責三件 事情: 
 

1)從給定的類名初始化應用程序對象,也就是初始化UIApplication或者子類對象的一個實例,如果你在這裏給定的是nil,那麼 系統會默認UIApplication類,也就主要是這個類來控制以及協調應用程序的運行。在後續的工作中,你可以用靜態方法sharedApplication 來獲取應用程序的句柄。 
 

2)從給定的應用程序委託類,初始化一個應用程序委託。並把該委託設置爲應用程序的委託,這裏就有如果傳入參數爲nil,會調用函數訪問 Info.plist文件來尋找主nib文件,獲取應用程序委託。 
 

3)啓動主事件循環,並開始接收事件。 
 

上面是UIApplicationMain函數的工作,接下來一個問題是應用程序視圖的顯示、消息的控制怎麼辦?下面就是UIApplication(或 者子類)對象的職責,這個對象主要做下面幾件事: 
 

1)負責處理到來的用戶事件,並分發事件消息到應該處理該消息的目標對象(sender,  action)。 
 2)管理以及控制視圖,包括呈現、控制行爲、當前顯示視圖等。 
 3)該對象有一個應用程序委託對象,當一些生命週期內重要事件(可以包括系統事件或者生命週期控制事件)發生時,應用程序通知該對象。例如,應用程序啓 動、內存不夠了或者應用程序結束等,讓這些事件發生時,應用程序委託去響應。 
 


通 過上面的分析,可以知道UIApplication對開發者來說,是一個黑箱,它也可以是。因爲所有的操作,都可以由它的委託來幫我們完成,它只需要在 後面維護一些不可更改的東西,如事件消息分發和傳遞、給委託發送事件處理請求等等,如,應用程序加載處理完畢,它會發送消息給委託,然後委託可以在 applicationDidFinishLanching委託函數中去實現開發者想要的動作。利用XCODE在創建應用程序時,會默認實現一個應用程序 委託類。而對於加載的視圖,則有視圖相關的委託類來處理視圖加載過程的生命事件。下面說明委託主要可以辦哪些事情: 
 控制應用程序的行爲 
 

- (void)applicationDidFinishLaunching:(UIApplication *)application 
           應用程序啓動完畢。 
 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
         當由於其它方法打開應用程序(如URL指定或者連接),通知委託啓動完畢 
 - (void)applicationWillTerminate:(UIApplication *)application 
          通知委託,應用程序將在關閉 退出,請做一些清理工作。 
 - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application 
         通知委託,應用程序收到了爲來自系統的內存不足警告。-(void)applicationSignificantTimeChange:(UIApplication *)application 
       通知委託系統時間發生改變(主要是指時間屬性,而不是具體的時間值) 
 打開URL 
 - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url 
            打開指定的URL 
 控制狀態欄方位變化 
 – application:willChangeStatusBarOrientation:duration: 
         設備方向將要發生改變 
 – application:didChangeStatusBarOrientation: 
 活動狀態改變 
 - (void)applicationWillResignActive:(UIApplication *)application 
    通知委託應用程序將進入非活動狀態,在此期間,應用程序不接收消息或事件。-(void)applicationDidBecomeActive:(UIApplication *)application 
       通知委託應用程序進入活動狀態,請恢復數據 
 

1.設置icon上的數字圖標
 
    //設置主界面icon上的數字圖標,在2.0中引進, 缺省爲0
     [UIApplicationsharedApplication].applicationIconBadgeNumber = 4;
 
2.設置搖動手勢的時候,是否支持redo,undo操作
 
   //搖動手勢,是否支持redo undo操作。
    //3.0以後引進,缺省YES
     [UIApplicationsharedApplication].applicationSupportsShakeToEdit =YES;
 
3.判斷程序運行狀態
 
    //判斷程序運行狀態,在2.0以後引入
    
   if([UIApplicationsharedApplication].applicationState ==UIApplicationStateInactive){
         NSLog(@"程序在運行狀態");
     }
 
4.阻止屏幕變暗進入休眠狀態
 
   //阻止屏幕變暗,慎重使用,缺省爲no 2.0
     [UIApplicationsharedApplication].idleTimerDisabled =YES;
 
慎重使用本功能,因爲非常耗電。
 
5.顯示聯網狀態
 
    //顯示聯網標記 2.0
     [UIApplicationsharedApplication].networkActivityIndicatorVisible =YES;
 
6.在map上顯示一個地址
 
   NSString* addressText =@"1 Infinite Loop, Cupertino, CA 95014";
    // URL encode the spaces
     addressText =  [addressTextstringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
    NSString* urlText = [NSStringstringWithFormat:@"http://maps.google.com/maps?q=%@", addressText];
    
    [[UIApplicationsharedApplication]openURL:[NSURLURLWithString:urlText]];
 
7.發送電子郵件
 
   NSString *recipients =@"mailto:[email protected][email protected],[email protected]&subject=Hello from California!";
    NSString *body =@"&body=It is raining in sunny California!";
    
    NSString *email = [NSStringstringWithFormat:@"%@%@", recipients, body];
     email = [emailstringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    
    [[UIApplicationsharedApplication]openURL:[NSURLURLWithString:email]];
 
8.打電話到一個號碼
 
   // Call Google 411
     [[UIApplicationsharedApplication]openURL:[NSURLURLWithString:@"tel://8004664411"]];
 
9.發送短信 
    // Text to Google SMS
     [[UIApplicationsharedApplication]openURL:[NSURLURLWithString:@"sms://466453"]];
 
10.打開一個網址
 
   // Lanuch any iPhone developers fav site
     [[UIApplicationsharedApplication]openURL:[NSURLURLWithString:@"http://itunesconnect.apple.com"]];
 

可以看到UIApplication的頭文件實現 
 @interface UIApplication :UIResponder <UIActionSheetDelegate>{ 
 @package 
 id<UIApplicationDelegate> _delegate ;  //這就是應用程序委託。 
 NSTimer ....... 
 } 
 因此,在UIApplication中處理的系統事件時,只需轉到_delegate這個類去處理, 這個類對象就是應用程序委託對象。我們可以從應用程序的單例類對象中得到應用程序委託的對象 
 UIApplicationDelegate* myDelegate = [[UIApplication sharedApplication] delegate]; 
 
UIApplication 接收到所有的系統事件和生命週期事件時,都會把事件傳遞給UIApplicationDelegate進行處理,對於用戶輸入 事件,則傳遞給相應的目標對象去處理。比如我們在應用程序被來電等消息後,可以調用應用程序委託類的 applicationWillResignActive()方法,這個方法在用戶鎖住屏幕時,也會調用,與之相適應的是應用程序重新被用戶打開時的委託 方法。另外常用的就是內存不足的系統警告,此時會調用應用程序委託類的applicationDidReceiveMemoryWarning()方法, 然後我們就可以試着釋放一些內存了。 
 
上面就是應用程序生命週期(啓動,中止,恢復,退出等過程)的應用程序處理UIApplication sharedApplication


另一篇介紹UIApplication的好文章:http://www.cnblogs.com/wendingding/p/3766347.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章