ios應用程序啓動過程

iOS 應用程序運行流程





UIApplicationMain
  main.m main 函數中執行了 UIApplicationMain 這個方法,這 是 ios 程序的入口點  
intUIApplicationMain (intargc,char*argv[], NSString *principalClassName, NSString *delegateClassName)  
  argc argv : ISO C 標準 main 函數的參數,直接傳遞 給 UIApplicationMain 進行相關處理便可  
  principalClassName :指定應用程序類,該類必須 是 UIApplication ( 或子類 ) 。若是爲 nil, 則用 UIApplication 類 做爲默認值  
  delegateClassName :指定應用程序類的代理類,該類必須遵 守 UIApplicationDelegate 協議  

UIApplicationMain
  此函數會根據 principalClassName 建立 UIApplication   對象,根據 delegateClassName 建立一個 delegate 對象 ,並將該 delegate 對象賦值給 UIApplication 對象中 的 delegate 屬性
  UIApplication 對象會依次給 delegate 對象發送不一樣的 消息,接着會創建應用程序的 main runloop (事件循環) ,進行事件的處理 ( 首先會調用 delegate 對象的
application:didFinishLaunchingWithOptions:)
  程序正常退出時這個函數才返回。若是進程要被系統強制 殺死,通常這個函數還沒來得及返回進程就終止了


  若是設置了主 xib 文件(在 Info.plist 中指定 , key NSMainNibFile ),就會在主 xib 文件中 尋找 UIApplication 和鏈接它的 delegate 。因 此在主 xib 文件中, File’s Owner 必須 爲 UIApplication( 或子類 ) ,而且創建一個遵 守 UIApplicationDelegate delegate 對象, 創建 UIApplication delegate 對象的關聯關係
四大對象關係圖


iOS 中的 mvc
 

UIApplication
  UIApplication 是應用程序的核心,每個程序在運行期必須 有 UIApplication (或子類)的一個實例( 有且僅有一個 ),通 過 [UIApplication sharedApplication] 能夠獲得這個單例實例 的指針
  UIApplication 幫助管理應用程序的生命週期,而它經過 delegate   來履行這個任務
  UIApplication 能夠接收事件,把全部用戶事件都放入隊列,逐個 處理,它會發送當前事件給一個合適的目標控件進行處理。它還將 部分   事件轉給 delegate 對象來處理 ,delegate 可處理的事件包括:應用程 序的生命週期事件 ( 如程序啓動和關閉 ) 、系統事件 ( 如來電 )


UIApplication
  [UIApplication sharedApplication].windows :   在本應用中打開的 UIWindow 列表,這樣就能夠接觸應用
中的任何一個 UIView 對象
  [UIApplication sharedApplication].keyWindow :   用來接收 鍵盤 以及 非觸摸類 的消息事件的 UIWindow ,而
且程序中每一個時刻只能有一個 UIWindow keyWindow   若是某個 UIWindow 內部的文本框不能輸入文字,多是 由於這個 UIWindow 不是 keyWindow

下面是這個類的一些功能:
1. 設置 icon 上的數字圖標
// 設置主界面 icon 上的數字圖標,在 2.0 中引進,   缺省爲 0
[UIApplicationsharedApplication].applicationIconBadgeNumber = 4;
2.
設置搖動手勢的時候,是否支持 redo,undo 操做
//
搖動手勢,是否支持 redo undo 操做。
//3.0
之後引進,缺省 YES
[UIApplicationsharedApplication].applicationSupportsShakeToEdit =
YES ;
3. 判斷程序運行狀態
// 判斷程序運行狀態,在 2.0 之後引入
/*
UIApplicationStateActive,
UIApplicationStateInactive,
UIApplicationStateBackground
*/
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:first@example.com?cc=second@example.com,third@example.com&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 favsite
[[UIApplicationsharedApplication]openURL:[NSURLURLWithString:@" http://itunesconnect.apple.com "]];

UIApplicationDelegate
  在開發過程當中, UIApplication 是一個很是重要的全局對象。但在實 際編程中咱們並不直接和 UIApplication 對象打交道,而是和其代理 打交道,它的代理必須遵照 UIApplicationDelegate 協議,代理 ��   供了相關的生命週期方法來處理應用程序的系統事件
>
    ios 設備的內存極其優先,若是爲 app 分配了太多內存,操做系統會終 止 app 的運行,在 UIApplication 接收到這個事件後它會調用代理 的 applicationDidReceiveMemoryWarning 方法,代理在這個方 法內能夠進行釋放內存的操做以防止操做系統強制終止應用程序的運行
>
 
>
  UIApplicationDelegat
>
    ios 並非多任務的操做系統,因此 app 很容易受到打擾。好比一個來 電可能致使 app 失去焦點,若是這個時候接聽了電話,那麼 app 會自動 終止運行  
>
    還有不少其它相似的事件會致使 app 失去焦點
>
    app 失去焦點前 會調用代理的 applicationWillResignActive  
>
    app 再次獲取焦點 時會調用代理的 applicationDidBecomeActive  
>
    在運行 app 鎖屏 會調用代理的 applicationWillResignActive  
>
    屏幕被解鎖 時,會調用代理的 applicationDidBecomeActive
>
  UIApplicationDelegate 生命週期方法說明
>
  1 - ( void )applicationWillResignActive:(UIApplication *)application
> / /
從主動到非活動狀態的應用程序時發送。這可致使產生某些類型的臨時中斷(如傳入電話呼叫或 SMS 消息)   ,或者當用戶退出應用程序,它開始過渡到的背景狀態。
>     / /
使用此方法暫停正在進行的任務,禁用定時器,踩下油門, OpenGL ES 的幀速率。遊戲應該使用這種方法來暫停遊戲。
>
 
>
  2 - ( void )applicationDidBecomeActive:(UIApplication *)applicatio
>
  說明:當應用程序入活動狀態執行,這個恰好跟上面那個方法相反
>
  3 - ( void )applicationDidEnterBackground:(UIApplication *)application
>
  說明:當程序被推送到後臺的時候調用。因此要設置後臺繼續運行,則在這個函數裏面設置便可
> / /
使用這個方法來釋放共享資源,保存用戶數據,廢止定時器,並存儲足夠的應用程序狀態信息的狀況下被終止後,將應用程序恢復到目前的狀態。
>     / /
若是你的應用程序支持後臺運行,這種方法被調用,而不是 applicationWillTerminate  :當用戶退出。
>
 
>
  4 - ( void )applicationWillEnterForeground:(UIApplication *)applicatio
>
  說明:當程序從後臺將要從新回到前臺時候調用,這個恰好跟上面的那個方法相反。
>
  5 - ( void )applicationWillTerminate:(UIApplication *)applicatio
>
  // 不支持多任務的時候調用
>
>
  說明:當程序將要退出是被調用,一般是用來保存數據和一些退出前的清理工做。這個須要要設置 UIApplicationExitsOnSuspend 的鍵值(自動設置)。
>
  6 - ( void )applicationDidReceiveMemoryWarning:(UIApplication *)applicatio
>
  說明: iPhone 設備只有有限的內存,若是爲應用程序分配了太多內存操做系統會終止應用程序的運行,在終止前會執行這個方法,一般能夠在這裏進行內存清理工做防止程序被終止
>
  7 - ( void )applicationSignificantTimeChange:(UIApplication*)applicatio
>
  說明:當系統時間發生改變時執行
>
  8 - ( void )applicationDidFinishLaunching:(UIApplication*)applicatio
>
  說明:當程序載入後執行
>
  9 - ( void )application:(UIApplication)application willChangeStatusBarFrame:(CGRect)newStatusBarFram
>
  說明:當 StatusBar 框將要變化時執行
>
  10 - ( void )application:(UIApplication*)application willChangeStatusBarOrientation
> (UIInterfaceOrientation)newStatusBarOrientatio
> duration:(NSTimeInterval)duratio
>
  說明:當 StatusBar 框方向將要變化時執行
>
  11 - ( BOOL )application:(UIApplication*)application handleOpenURL:(NSURL*)ur
>
  說明:當經過 url 執行
>
  12 - ( void )application:(UIApplication*)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientatio
>
  說明:當 StatusBar 框方向變化完成後執行
>
  13 - ( void )application:(UIApplication*)application didChangeSetStatusBarFrame:(CGRect)oldStatusBarFram
>
  說明:當 StatusBar 框變化完成後執行
>
 
>
  UIWindow
>
    UIWindow 是一種特殊的 UIView ,一般在一個 app 中只會有一 個 UIWindow ,但能夠手動建立多個 UIWindow  
>
    UIWindow 的主要做用 :  
>
  1   供一個區域來顯示視
>
  2   將事件分發給視
>
  3   UIViewController 協同工做,方便完成設備方向旋轉的支持
>
 
>
  UIWindow
>
  添加 UIView UIWindow 中兩種常見方式 :
>
  1   addSubview :直接將 UIView 添加到 UIWindow 中,程序負責維 護 UIView 的生命週期以及刷新,但並不會理會 UIView 對應 的 UIViewController
>
  2   rootViewController :自動將 UIViewController 對應的 UIView   添加到 UIWindow 中,同時負責維護 UIViewController UIView 的 生命週期
>
    經常使用方
>
  1   makeKeyWindow : 讓當前 UIWindow 變成 keyWindo
>
  2   makeKeyAndVisible : 讓當前 UIWindow 變成 keyWindow ,並顯示出來
>
 
>
  UIViewControlle
>
    UIViewController 屬於 MVC 模型中的 C(Controller), 說的更具體 點它是一個視圖控制器 , 管理着一個視圖 (UIView)
>
    一個 UIViewController 應該只管理一個 view hierarchy ,一般 來講一個完整的 view hierarchy 指的是佔滿整一個屏幕。而不少 ap p 滿屏中會有各個區域分管不一樣的功能,一些開發者喜歡直接新建一 個 UIViewController 和一套相應的 view 來完成所要的功能,這樣 作徹底不符合 Apple �� 供的設計規範 UIViewController view html

  能夠利用 xib 文件來初始化 view;   也可使用自定義view ,那就必須覆蓋 loadView 方法來建立這個 viewUIViewController view lazy loading , 當你訪 問其 view 屬性時 ,view 會從 xib 文件載入或者經過代碼創 建 ( 覆蓋 loadView 方法 , 自定義其 view hierarchy) ★  能夠用 isViewLoaded 方法判斷一個 UIViewController   view 是否已經被加載 UIViewController 生命週期方法的
r>
    view 加載後調用 viewDidLoad , 這裏能夠進行一些數據的請求或加載 , 用來更新界面 view 將要被加入 view hierarchy 時調用 viewWillAppear , 完成  加入時調用 viewDidAppear   view 將要從 view hierarchy 中移除時調用 viewWillDisappear  , 完成移除時調用 viewDidDisappear     當內存緊張時 ,   調用 didReceiveMemoryWarning , 其默認實現是如 果當前 UIViewController view superview nil, 則將 view 釋 放且調用 viewDidUnload ,   viewDidUnload 中你能夠進行後繼的內 存清理工做 ( 主要是界面元素的釋放 , 當再次加載的時候須要重建 )  (這裏的 view 是指 UIViewController 內部的 view 屬性)   工程名 -Info.plist ios

  創建一個工程後,會在 Supporting files 文件夾下看到一個 工程名   -Info.plist 的文件,該文件對工程作一些運行期的配置,很重要, 不能刪除     在舊版本 Xcode 建立的工程中,這個配置文件的名字就叫 Info.plist 編程

  若是使用文本編輯器打開這個文件,會發現這是一個 XML 格式的文本  文件,通常不用文本編輯器直接編輯這個文件,而是經過 Xcode 編輯 windows

  項目中還有一個 InfoPlist.strings 的文件,跟 Info.plist 文件的 本地化相關   工程名 -Info.plist mvc

  常見屬性 ( 紅色部分是用文本編輯器打開時看到的 key) app

  Localiztion native development region( CFBundleDevelopmentRegion ) - 本地化相關     Bundle display name( CFBundleDisplayName ) - 程序安裝後顯 示的名稱 , 限制在 10 - 12 個字符,若是超出,將被顯示縮寫名稱 框架

  Icon file( CFBundleIconFile ) -app 圖標名稱 , 通常爲 Icon.png 編輯器

  Bundle version( CFBundleVersion ) - 應用程序的版本號,每次  往 App Store 上發佈一個新版本時,須要增長這個版本號 ide

  Main nib file base name( NSMainNibFile ) - nib 文件的名稱 函數

  Bundle identifier( CFBundleIdentifier ) - 項目的惟一標識, 部署到真機時用到   工程名 -Prefix.pch

  通常來講,能夠將項目中常常用到的一些頭文件放在這裏來 import , 整個項目均可以訪問這個文件的內容,這樣既節省了手動添加 import 的時間,也有助於加速編譯

  在這裏定義的宏,整個項目均可以訪問   pch 文件中添加下列預處理指令,而後在項目中使用 Log(...) 來輸出 日誌信息,就能夠在發佈應用的時候,一次性將 NSLog 語句移除(在調 試模式下,纔有定義 DEBUG )  #ifdef DEB
r> #define  Log(...) NSLog(__VA_ARGS_
r>
  #el
r> #define
  Log(...)   /*
r>
  #end
r>
  r>  

開發iOS6 的注意

  iOS6 新特性: auto layout 屬性,此屬性只針 iOS6 及以上版本   iOS6 如下版本運行時可能會出現的異常信息: Terminating app due to uncaug
r> excepti
r> ‘NSInvalidUnarchiveOperationException
r> reason: ‘Could not instantiate cla
r> named NSLayoutConstrain
r>
    具體場景: Xcode 4.5   選擇 iPhone/iPad 5.0/5.1 Simulator (模擬器)   解決辦法:須要關閉 storyboard xib 界面文 件的 Use Autolayout   選項,這是由於 Auto Layout 特性是 iOS 6 新增長的,在以前的   5.0/5.1 Simulator 模擬器中不支持 nib 文件

★  nib 文件是 iOS 中用來 述視圖的 xml 格式的 文本文件, 如今拓展名爲 xib ,用 Interface Builder 打開能夠 生成圖形界面式的

  某書中著名的一句話 :Interface Builder 把窗口、 菜單欄以及窗口上的各類控件對象都 凍結 在一個 NIB   文件裏 ; 程序運行時,這些對象將會 甦醒

  加載 Nib 文件時,會將文件中的 述轉化爲應用程序可 以操做的真正對象,全部在 Interface Builder 中建 立的關聯(如 File’s Owner 和其餘對象之間的關聯) 都可以在運行時從新創建起來   nib 文件

★  nib 文件是指應用程序一啓動就裝載的 nib 文件,它 的 File’s Owner 必定要是個 UIApplication( 或子類 )   ,而且新建一個 delegate 對象、創建 UIApplication   delegate 對象的關聯 nib 文件的設置方法 r>   Info.plist 經過 NSMainNibFile 這個 key 能夠設置主 nib 文件 nib 文件的設置方法
r>
  Summary Main Interface
r>
  UIView ★  UIView iOS 中界面元素的基礎,全部的界面元素都繼承它,能夠說 在 iPhone 中你能看到的、摸到的,都是 UIView ★  UIView 的基本功
r>
  1   繪圖和動畫 ( CALayer CAAnimation 實現
r>
  2   事件處理 ( 繼承了 UIRsponde
r>
    一個 UIView 能夠包含和管理若干個子視圖,決定着子視圖的位置和大小 UIView 經常使用屬性

★  frame 父視圖 座標系中的位置 (CGPoint origin) 和大小 (CGSize size)

★  bounds 本視圖 座標系中的位置 (CGPoint origin x y 永遠爲 0) 和大 小 (CGSize size)

★  center
視圖的中點在 父視圖 座標系中的
r>
    UIView*superview
r>
    NSArray*subviews 全部的子
r>
    UIWindow *window   當前視圖所在的
r>
    BOOLuserInteractionEnabled YES 表明接收觸摸事件     在父視圖座標系中,父視圖的左上角爲座標原點 (0,
r>
    在本視圖座標系中,本視圖的左上角爲座標原點 (0, 0) UIKit 座標系
r>  (0,0) View1 View2 的父視圖   View2. frame   = {x=70,y=50,width=60,height=40} View2. bounds   = {x=0,y=0,width=60,height=40} View2. center   = (x=100, y=70) •  UIKit 框架中的座標系都如左圖所示,視圖的 左上角爲原點 (0,0) , x 軸向右正向延伸, y   軸向下正向延伸 •  View3 frame x , y
r>
  1   若是綠色視圖是 View3 的父視圖,那麼 View3 x , y 爲紅色箭頭的
r> 2
  若是 View1 View3 的父視圖,那麼 View3x , y 爲藍色箭頭的寬度 UIView 經常使用方法和屬性 ★  -(void)removeFromSuperview 從父視圖中移除 ( 當前視圖的計數器會 -1) ★  -(void)addSubview:(UIView*)view 添加一個子視圖 ( 新添加的子視圖在父視圖的最上面,子視圖的 計數器會 +1) ★  -(UIView*)viewWithTag:(NSInteger)tag   根據 tag 找到對應的子視圖 iOS 關閉鍵盤的方法 r>     調用 UIView endEditing 方法,例如 [self.view endEditing :YES];   成功關閉鍵盤的條件 :self.view 或者其子視圖是第一響應者 iOS 關閉鍵盤的方法 2

遞歸找到第一響應者,讓它把鍵盤給退
r>  [[self findFirstResponder:self.view] resignFirstResponder ]; - (UIView*)findFirstResponder:(UIView*)view   { for ( UIView *childView in view.subviews
r>  {   //   遍歷子視
r>
  if ( [childView respondsToSelector:@selector(isFirstResponder)] && [childView isFirstResponder] )  { return childView;  //   若是 childView 是第一響應
r>
  }       UIView *result = [self findFirstResponder:childView
r> if (result) return result
r>  } return nil; 

1.先執行main函數,main內部會調用UIApplicationMain函數

  2.UIApplicationMain函數裏面作了什麼事情:

  1> 建立UIApplication對象

  2> 建立UIApplication的delegate對象—–PYAppDelegate

  3> 開啓一個消息循環

  每監聽到對應的系統事件時,就會通知MJAppDelegate

  4> 爲應用程序建立一個UIWindow對象(繼承自UIView),設置爲PYAppDelegate的window屬性

  5> 加載Info.plist文件,讀取最主要storyboard文件的名稱

  6> 加載最主要的storyboard文件,建立白色箭頭所指的控制器對象

  7> 而且設置第6步建立的控制器爲UIWindow的rootViewController屬性(根控制器)

  8> 展現UIWindow,展現以前會將添加rootViewController的view到UIWindow上面(在這一步纔會建立控制器的view)

  [window addSubview: window.rootViewControler.view];

  進入main函數,在main.m的main函數中執行了UIApplicationMain這個方法,這是ios程序的入口點!

  int UIApplicationMain(int argc, char argv[], NSString principalClassName, NSString *delegateClassName)

  argc、argv:ISO C標準main函數的參數,直接傳遞給UIApplicationMain進行相關處理便可

  principalClassName:指定應用程序類,該類必須是UIApplication(或子類)。若是爲nil,則用UIApplication類做爲默認值

  delegateClassName:指定應用程序類的代理類,該類必須遵照UIApplicationDelegate協議

  此函數會根據principalClassName建立UIApplication對象,根據delegateClassName建立一個delegate對象,並將該delegate對象賦值給UIApplication對象中的delegate屬性

  lUIApplication對象會依次給delegate對象發送不一樣的消息,接着會創建應用程序的main runloop(事件循環),進行事 件的處理(首先會調用delegate對象的 application:didFinishLaunchingWithOptions:)

  程序正常退出時這個函數才返回。若是進程要被系統強制殺死,通常這個函數還沒來得及返回進程就終止了

  下面咱們有圖有真相吧!!!

Xcode4.2之後iOS應用的啓動順序變化


以上是Xcode4.2中不採用storyboard用的默流程於採用了storyboard用,UIApplicationMain()將會外加載應用的主要storyboard文件,從而建窗口和初始視圖

 

main()變化

 

main()仍然是用的起點,其代以下:

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

{

    @autoreleasepool {

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

    }

}

main()採用了新的@autoreleasepool{}函數,以便支持LLVM3.0。但化不會影響 的啓動順序。須要注意的是UIApplicationMain第四個參數的化,以前是nil,裏已更改了。若是看相關文檔(https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIKitFunctionReference/Reference/reference.html#//apple_ref/doc/uid/TP40006894-CH3-SW7,就會知道第四個參數表明「用的delegate初始化的名」,若是從用的主nib文件加代理象,參數指定nil

然,我用代理將不會由以前的MainWindow.xib,而是直接由UIApplicationMain()函數建。實際上,目中已再也不有MainWindow.xib文件。

 

 

Xcode4.2及之後版本去掉main nib文件的緣由極可能是storyboarding入。storyboards基於視圖控制器,而非視圖或窗口。

 

最後,non-storyboarding用,因爲取消了MainWindow.xib,所以在AppDelegate.m中的didFinishLauchingWithOptions:方法中就須要增長一些初始化的代,以下:

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions

{

    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    // Override point for customization after application launch.

  if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {

      self.viewController = [[ViewController alloc] initWithNibName:@"ViewController_iPhone" bundle:nil];

  } else {

      self.viewController = [[ViewController alloc] initWithNibName:@"ViewController_iPad" bundle:nil];

  }

  self.window.rootViewController = self.viewController;

    [self.window makeKeyAndVisible];

    return YES;

}

相關文章
相關標籤/搜索