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;

}

相关文章
相关标签/搜索