iOS程序启动原理
Posted on December 28th, 2013
iOS 程序启动原理
技术博客 http://www.cnblogs.com/ChenYilong/ 新浪微博http://weibo.com/luohanchenyilong
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
>
> 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
★ 可以利用 xib 文件来初始化 view; 也可以使用自定义 的 view ,那就必须覆盖loadView 方法来创建这个 view ★ UIViewController 的 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
★ 建立一个工程后,会在 Supporting files 文件夹下看到一个 ” 工程名 -Info.plist” 的文件,该文件对工程做一些运行期的配置,很重要, 不能删除 ★ 在旧版本 Xcode 创建的工程中,这个配置文件的名字就叫 ” Info.plist ”
★ 如果使用文本编辑器打开这个文件,会发现这是一个 XML 格式的文本 文件,一般不用文本编辑器直接编辑这个文件,而是通过 Xcode 编辑
★ 项目中还有一个 InfoPlist.strings 的文件,跟 Info.plist 文件的 本地化相关 工程名 -Info.plist
★ 常见属性 ( 红色部分是用文本编辑器打开时看到的 key)
★ Localiztion native development region( CFBundleDevelopmentRegion ) -本地化相关 ★ Bundle display name( CFBundleDisplayName ) - 程序安装后显 示的名称 , 限制在 10 - 12 个字符,如果超出,将被显示缩写名称
★ Icon file( CFBundleIconFile ) -app 图标名称 , 一般为 Icon.png
★ Bundle version( CFBundleVersion ) - 应用程序的版本号,每次 往 App Store上发布一个新版本时,需要增加这个版本号
★ 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 新特性: 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 选项,这是因为 AutoLayout 特性是 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)