原文地址:
http://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40007072-CH1-SW1
这里只是做一个简单的摘要翻译,方便自己记忆,错误难免,请参考原文。
1. 应用运行时环境
(1) 快速启动,短时间使用
iphone,ipad 等 iOS 设备的优势在于可以快速启动,而且可能只是使用一会又放回口袋或书包。在iOS4 之前,App 退出就会关闭,并从内存中移出。之后有了多任务(multitasking),退出的 app 转到后台,app 一直在后台直到重新启动或者从内存中移出。多任务可以使 app 重新启动更加迅速,由于内存的现实,系统会清除近期不再使用的内存,清除可能发生在任何时间并且没有提示。因此 app 转入后台时需要及时保存用户信息和 app 状态信息。当app 恢复到前台时可以使用这些 data.
(2) iOS 系统的特殊行为
iOS 核心是用与 Mac OS X 相同的技术,即 mach kernel 和 BSD interface, 所以 iOS 的app 是运行在一个 Unix-based 系统上的,系统支持 thread, sockets 和其他的技术,但是 iOS 系统也有一些特殊的特性。
[1] 虚拟内存系统 (the virtual memory system)
关于内存管理,iOS 本质上与 Mac OS X 系统相同,每个 iOS app 有独立的虚拟内存地址,但与 Mac OS X 不同 iOS 当内存满时它不支持 paging to disk, 而是简单的释放那些 read-only 的 memory page, 这些 read-only 的 memory page 当需要的时候可以重新加载回来。如果内存持续受限,系统会给所有的运行 app 发送 notice, 让app 释放不需要的内存, 每个 app 都需要响应这个 notification ,并且释放自己的无用内存缓解系统的内存压力。
[2]自动的睡眠时钟 The automatic sleep timer
iOS 系统节电的一个措施就是自动睡眠时钟。 当系统在一段时间内没有收到 touch 事件,这是自动睡眠时钟首先会让屏幕变暗,最终关闭屏幕。 如果你的app 不会触发 touch 事件,例如开发了一款使用重力加速计的游戏,你需要在程序中禁掉自动睡眠时钟,以防屏幕一段时间后自动关闭。只有那些需要屏幕显示而且不依赖 touch 事件的 app 才应该禁用自动睡眠时钟。
[3]多任务支持
(3)安全性 Security
[1]应用程序沙箱 the application sandbox
沙箱是一组良好定义的限制,限制 app 访问文件系统,网络资源,硬件,等。每个app 可以访问自己 sandbox 内的资源,但不能访问其他app sandbox 的资源。当系统第一次安装到设备上,系统会为 app 创建 home directory 和 一些关键的 subdirectory.
Home directory 类似于:
/ApplicationRoot/ApplicationID/
[2]文件保护 File Protection
在 iOS4 之后,app 可以使用文件保护特性,当设备被锁定后,无法访问被保护的文件,文件保护利用了设备硬件提供的特性 (例如 iphone 3GS 和 iphone 4).
[3] Keychain data
keychain 是一个加密的安全容器,用来保存 passwords 和 其他安全数据。keychain data 保存在 app 沙箱之外。 在iOS4 之前,keychain data 只能恢复到备份它的设备上,在iOS 4 之后 keychain data 可以恢复到符合条件的其它设备上。
(4) 文件系统 The file system
[1] 一些重要的 app 目录
<Application_Home>/AppName.app
这个是存放 app bundle 文件的目录,不要往这个目录中写入其他内容。在 iOS2.1 之后 ituns 同步时不会备份这个目录。ituns 在第一从 app store 购买应用并安装时会做一次同步备份,之后的同步不会备份。
<Application_Home>/Documents
这个目录存放用户 documents 和 app data files. 这个目录中的内容可以通过共享给用户。 ituns 同步时会备份此目录中的内容。
<Application_Home>/Library
这个目录是一个用来存放非用户文件的顶级目录,Library 目录下会有一些标准的子目录,你也可以添加自定义的子目录。这个目录下的内容,除 Caches 子目录外,会在ituns 同步时备份。
<Application_Home>/Library/Preferences
这个目录用来存放 app 指定的 preferences files.需要使用 NSUserDefaults 类 或者 CFPreferences API 来设置/获取 app preferences. 这个目录中的内容会被 ituns 备份。
<Application_Home>/Library/Caches
这个目录用来写入一些 app 的支持文件,比如app 启动后需要持久化的一些data,你的app 负责写入和移除此目录中的内容。在 iOS2.2 之后,这个目录内容不会被 ituns 备份。
<Application_Home>/tmp/
这个目录用来写入临时文件,而不是应用需要持久化的data. 当文件不再使用你的 app 应该负责删除这些内容。如果你的应用不再运行,系统会删除这个文件夹中的内容。iOS 2.1
之后这个文件夹的内容不会被 ituns 备份。
[2] 大小写敏感的文件系统
iOS 系统大小写敏感 Case-Sensitive
[3] 与 desktop 计算机共享文件
文件共享可以使你的 app 和 desktop 计算机之间共享文件。
(5) 备份和恢复 Backup and Restore
ituns 会自动处理 app 数据的备份和恢复,但你需要了解哪些目录中的内容会被备份
[1] 备份什么
你的 app 不需要为备份/恢复做什么特殊准备。在 iOS 2.2 之后,当设备连接到一个计算机并同步后,ituns 会自动增量备份所有文件,除了以下目录中的内容不会备份
尽管 ituns 会备份 app bundle 内容 (<Application_Home>/AppName.app),但是只是在第一次从 app store 上下载安装时备份,之后的连接同步不会备份这目录的内容。为了防止同步时间过长,你应该选择保存data 的目录, <Application_Home>/Documents 用来存放用户文档和 app data, 这些内容会被备份。对于临时产生的文件需要存放在 <Applicaiton_Home>/tmp 中,他不会被 ituns 备份。 如果你的 app 需要保存数据为下次 app 启动时使用,而且这些数据也不需要 ituns 备份,保存到文件<Application_Home>/Library/Caches 目录中。
(6) iOS 模拟器
你可以使用 iOS 模拟器来测试开发你的 app, 模拟器提供与设备相似的运行时环境,但不完全相同,很多限制只有在实际设备上才有,例如:不支持 paging to disk.还有 OpenGL ES 在设备和模拟器上的行为也不同。
[1] 检测硬件设备支持 Determining the available hardware support
如果你的 app 需要一个硬件支持才能运行,你需要将 UIRequiredDeviceCapabilities key 加入到 app 的 Info.plist 中,这个 key 会阻止用户将 app 安装到不支持该特性的device 上。
检查特性:
检查是否支持多任务
检查你需要配置 app 界面支持 ipad size, iphone size
检查是否有外接屏幕
检查是否有硬件级别的磁盘加密
检查是否有网络
检查是否有摄像头
检查是否支持视频录制
检查是否有 microphone
检查是否有GPS
检查是否有硬件加速计
检查当前电池水平
2.核心app 设计 the core application design
每个 iOS app 都构建在 UIKit 框架之上,有相似的架构。 系统和运行的app 之间有很多的交互,很多交互都被 UIKit 底层处理了。 UIKit 提供 hooks 给我们的代码,来实现我们需要的行为。
(1)iOS app 使用的设计模式
Model-View-Controller
MVC 将你的代码分为不同的部分。 model 定义 app的数据部分,view 定义用户界面,controller 是 model 和 view 之间的桥梁,连接并在他们之间传递数据。
Block objects
Block objects 用来封装 code 和 local stack 到一个 form 为了以后执行使用,iOS 4 之后开始支持 Block objects, 常被异步操作的回调使用。
Delegation
代理模式,是处理复杂对象而不用子类化他们的一种方式。将代码放到一个代理对象中,而不是去实现一个复杂对象的子类。复杂对象去调用代理对象的方法,从而执行你的代码。
Target-action
Controls 使用 target-action 模式来反映交互,例如用户点击按钮,control 将事件发送给你。
Manage memory model
Objective-C 使用引用计数器来决定何时释放对象的内存
Threads and concurrent programming
所有版本的iOS 都支持多线程, iOS 4 之后还支持 Grand Central Dispatch (GCD) 并发执行任务。
(2) 核心对象 the core application objects
从你的 app 被用户启动,到 app 推出, UIKit 框架管理大部分的 app 行为。例如,一个iOS app 不断从系统接收各种事件, app 必须对这些事件做出响应。 接收事件是 UIApplication 对象的工作,对事件作出响应需要你编写代码来完成。其他的部分也类似,系统对象来管理整体过程,你写的代码用来实现特定的行为。
图2-1 iOS app 中的关键对象
UIApplication object
UIApplication 对象管理 application 的 event loop, 你自己实现的 application-level 级的代码在 delegate 类中。
Application delegate 对象
Data model object
View controller object
View controller 对象管理 app 中展示界面内容,管理 view 和 data model 对象间的交互, UIViewController 是所有 view controller 对象的基类。 它对 view 提供了一些默认的支持,如 处理 device 的旋转,和其他标准的系统行为。
UIWindow Object
UIWindow 对象配合展示一个或多个 view , 大部分 iOS app 只有一个 window,app 可以更改window 中的内容,通过修改其中的 view (一般通过 view controller 对象完成)。
Views, controls, and layers
Views 和 controls 对象提供了app 中的界面内容。 A view 对象绘制页面上的一个矩形区域,并相应其中发生的事件。 控件 (controlls) 是一些响应特定事件的view, 比如:buttons, text fields, toggle switch.
可以通过子类 UIView 来实现订制的 view
(3)iOS应用程序的生命周期 The Appliation Life Cycle
iOS app 的生命周期是指发生在 app 启动和终止之间的一系列事件。 用户通过点击图标启动app , 系统显示 app 的启动画面,启动 app 是通过调用 main () 方法,之后 UIKit 框架会做很多初始化工作, 载入 app 的 main nib file, 准备好event loop.
图 2-2 是一个简化的 app 生命周期,描述了从一个 app 启动到另一个app 启动之间的过程。在app 生命周期中的关键点, UIKit 会发送消息给 delegate 对象,让 delegate 对象知道发生了什么, 在 event loop 之中,UIKit 还会将事件分发给注册的 event handler, 这些可能是 view 或 view controller
图2-2 App 生命周期
[1] main 函数 the main function
象其他的 C-based app 一样,main 函数是 iOS app 的入口,在 iOS app 中 main 的作用很少,主要是将控制交给 UIKit framework, 因此用 xcode 创建的 app 都类似如下:
UIApplicationMain 类是 main 函数的核心。
[2] app 代理 the application delegate
监控 app 的 high-level 行为是 application delegate 类的职责。 使用 delegate 可以避免去子类化 UIKit 中的复杂对象,我们将相应代码写在代理类中,当事件发生时, UIKit 的复杂对象会将event 传递给代理类,在代理类中实现响应事件的代码。
重要 delegate 模式可以简化你的 app 开发,为你节省时间,因此是一种重要的模式。
[3] 了解app 的状态转换 Understanding an Application's States and Transitions
在 iOS 4 系统之后运行在其中的 app 可以处于以下几种状态
Not running
应用程序没有启动或者医被系统关闭
Inactive
app 在前台运行,但当前不接收 event 事件。一个 app 一般在状态转换时会处在 Inactive 状态,当用户所屏幕后 app 处于 Inactive 状态,或者系统提示用户响应一些事件时处于 Inactive 状态,比如来了电话或 SMS 消息事件。
Active
app 在前台运行,并且接受 event 事件。
Background
app 在后台并且在运行中。 大部分程序在 进入 suspended 状态之前会经过 backgound 状态,然后,一些app 会在 backgound 状态执行一段时间。也有一些应用启动后直接进入backgound 状态而不是 active 状态。 iOS 4 之后才有 background 状态。
Suspended
app 在后台并且没有执行的状态,app 处于 suspended 状态,本质上在后台的一种冰冻状态,当系统内存不足时,系统会收取 suspended app 的内存并没有通知。
状态转化时,系统会调用 delegate 对象的如下方法:
application:didFinishLaunchingWithOptions:
applicationDidBecomeActive:
applicationWillResignActive:
applicationDidEnterBackground
applicationWillEnterForeground:
applicationWillTerminate:
启动应用程序 Launching the application
在启动时, app 从 not running 状态转换到 Active 或 background 状态。app 会调用 delegate 对象的 application:didFinishLaunchingWithOptions: 方法,之后调用 applicationDidBecomeActive 或者 applicationDidEnterBackground 方法 (这依赖于应用程序是转换到 foreground 执行还是 background 执行)
图 2-3 启动应用程序进入 active 状态
方法 application:DidFinishLaunchingWithOptions: 负责启动时的大部分工作,有如下的职责:
你应该让 application:DidFinishLaunchingWithOptions: 方法尽量轻量级,尽管你可能有很多的初始化工作需要在该方法中完成,但你只有大约 5 秒的时间来完成初始化并返回。但如果超时系统会终止你的 app 因为没有及时响应。使他轻量级需要将一些初始化任务异步操作或者为时间长的task 单起一个线程。尤其是那些需要 internet 连接的初始化任务。
转移到后台 move to the background
当用户按了 home 键,或者启动了另外一个 app, 前台的 app 将会先变为 inactive 状态然后进入 background 状态,这会调用代理类的 applicationWillResignActive 和 applicationDidEnterBackground: 方法。
图2-4 展示了大部分 app 进入 backgound 状态后将进入 suspended 状态,如果 app 要求再执行一段时间或者 app 声明了可以在后台执行,它会在方法return 后继续执行。
图 2-4 应用程序从前台转到后台
当 app 转到后台,你的app 核心对象会被保留,包括你的 custom objects 和 数据结构和你的 应用程序控制对象,window, views 和 layers, 系统会释放屏幕后对象的内存。
方法 applicationDidEnterBackground 有大约 5 秒时间完成task 并返回,实际中这个方法应该尽可能快的返回,如果超时app 将会被系统中止,并释放相关内存。如果你仍然需要一些时间去执行task, 可以调用 beginBackgroundTaskWithExpirationHandler: 在后台执行一段时间,然后为长任务启动一个新的线程。
有两件事需要在方法 applicationDidEnterBackgrond: 中做:
响应中断 Responding to interruptions
当一个临时中断发生(如电话或短信), app 会临时进入 inactive 状态,然后等待用户选择接受或忽略这个中断,如果忽略中断 app 会重新进入 active 状态,如果接受中断 app 将进入 background state。
图 2-5 处理应用程序中断
恢复前台执行 resume foreground execution
用户重新启动一个在后台的app 时,系统先将 app 状态变为 inactive ,之后再变为 active, 系统会调用代理的 applicationWillEnterForeground: 和 applicationDidBecomeActive: 方法。 如图 2-6 所示:
图2-6 从background 转换到 froeground
[img]http://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Art/transition_bgtoact.jpg
[/img]
当app 到前台后,应该恢复app 的服务,并可以处理收到的event.
注意: 当你的app 将要转到前台,系统会发送一个通知 UIApplicaitonWillEnterForegroundNotification. 你的对象可以在接收到这个通知后重新注册自己。
当 app 处于 suspended 状态,系统会积累合并收到的event,当app 重新运行,系统将这些event 传递给app, app 根据这些event 做出相应的响应。 例如设备的方向改变了,你的app的 view controller 会自动更新 app 的方向。
响应 app 结束 responding to application termination
app 一般会转移到 backgoround 然后进入 suspended 状态,但如果满足以下你的 app 会被关闭,占用的内存被回收。
你的 app 在运行(在 foreground 或者 background),当结束 app 是,系统会调用代理类的 applicationWillTerminate: 方法, 你可以在该方法中执行一些清理工作。也在这个方法中保存 user data 和 app 状态信息,以便下次启动时进入这个状态。你必须在 5 秒内完成这些工作并返回,否则系统会强制关闭你的 app ,并清除内存。 如果你的 app 处于suspended 状态,系统不会调用 applicationWillTerminate: 方法。
使用 iOS4 以后的系统,你也需要为app 的结束做准备,用户可以显示的通过Mulititasking UI 来结束 app, 如果系统内存紧张,系统也会清除一些app 来获得内存空间,如果你的 app 在 supseneded 状态,系统会在没有提示的情况下回收你app 的内存。如果你的app 在 background 运行,系统会调用 applicationWillTerminate 方法,你的 app 不能在这个方法中要求更多的执行时间。
多任务 Multitasking
在 iOS4 之后, 多个app 可以在内存中同时运行。只有一个 app 在前台,其他的app 在background 中。 app 必须考虑在 foregrond 和 background 之间的转换。
为支持多任务app 需满足如下条件:
开发一个支持多任务执行的app Being a Responsible, Multitasking-Aware Application
在前台运行的app 对系统资源和硬件有优先权,因此 app 在前后台状态转换时需要修改它们的行为。特别是,当app 转到后台执行需要遵循以下守则:
http://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40007072-CH1-SW1
这里只是做一个简单的摘要翻译,方便自己记忆,错误难免,请参考原文。
1. 应用运行时环境
(1) 快速启动,短时间使用
iphone,ipad 等 iOS 设备的优势在于可以快速启动,而且可能只是使用一会又放回口袋或书包。在iOS4 之前,App 退出就会关闭,并从内存中移出。之后有了多任务(multitasking),退出的 app 转到后台,app 一直在后台直到重新启动或者从内存中移出。多任务可以使 app 重新启动更加迅速,由于内存的现实,系统会清除近期不再使用的内存,清除可能发生在任何时间并且没有提示。因此 app 转入后台时需要及时保存用户信息和 app 状态信息。当app 恢复到前台时可以使用这些 data.
(2) iOS 系统的特殊行为
iOS 核心是用与 Mac OS X 相同的技术,即 mach kernel 和 BSD interface, 所以 iOS 的app 是运行在一个 Unix-based 系统上的,系统支持 thread, sockets 和其他的技术,但是 iOS 系统也有一些特殊的特性。
[1] 虚拟内存系统 (the virtual memory system)
关于内存管理,iOS 本质上与 Mac OS X 系统相同,每个 iOS app 有独立的虚拟内存地址,但与 Mac OS X 不同 iOS 当内存满时它不支持 paging to disk, 而是简单的释放那些 read-only 的 memory page, 这些 read-only 的 memory page 当需要的时候可以重新加载回来。如果内存持续受限,系统会给所有的运行 app 发送 notice, 让app 释放不需要的内存, 每个 app 都需要响应这个 notification ,并且释放自己的无用内存缓解系统的内存压力。
[2]自动的睡眠时钟 The automatic sleep timer
iOS 系统节电的一个措施就是自动睡眠时钟。 当系统在一段时间内没有收到 touch 事件,这是自动睡眠时钟首先会让屏幕变暗,最终关闭屏幕。 如果你的app 不会触发 touch 事件,例如开发了一款使用重力加速计的游戏,你需要在程序中禁掉自动睡眠时钟,以防屏幕一段时间后自动关闭。只有那些需要屏幕显示而且不依赖 touch 事件的 app 才应该禁用自动睡眠时钟。
[3]多任务支持
(3)安全性 Security
[1]应用程序沙箱 the application sandbox
沙箱是一组良好定义的限制,限制 app 访问文件系统,网络资源,硬件,等。每个app 可以访问自己 sandbox 内的资源,但不能访问其他app sandbox 的资源。当系统第一次安装到设备上,系统会为 app 创建 home directory 和 一些关键的 subdirectory.
Home directory 类似于:
/ApplicationRoot/ApplicationID/
[2]文件保护 File Protection
在 iOS4 之后,app 可以使用文件保护特性,当设备被锁定后,无法访问被保护的文件,文件保护利用了设备硬件提供的特性 (例如 iphone 3GS 和 iphone 4).
[3] Keychain data
keychain 是一个加密的安全容器,用来保存 passwords 和 其他安全数据。keychain data 保存在 app 沙箱之外。 在iOS4 之前,keychain data 只能恢复到备份它的设备上,在iOS 4 之后 keychain data 可以恢复到符合条件的其它设备上。
(4) 文件系统 The file system
[1] 一些重要的 app 目录
<Application_Home>/AppName.app
这个是存放 app bundle 文件的目录,不要往这个目录中写入其他内容。在 iOS2.1 之后 ituns 同步时不会备份这个目录。ituns 在第一从 app store 购买应用并安装时会做一次同步备份,之后的同步不会备份。
<Application_Home>/Documents
这个目录存放用户 documents 和 app data files. 这个目录中的内容可以通过共享给用户。 ituns 同步时会备份此目录中的内容。
<Application_Home>/Library
这个目录是一个用来存放非用户文件的顶级目录,Library 目录下会有一些标准的子目录,你也可以添加自定义的子目录。这个目录下的内容,除 Caches 子目录外,会在ituns 同步时备份。
<Application_Home>/Library/Preferences
这个目录用来存放 app 指定的 preferences files.需要使用 NSUserDefaults 类 或者 CFPreferences API 来设置/获取 app preferences. 这个目录中的内容会被 ituns 备份。
<Application_Home>/Library/Caches
这个目录用来写入一些 app 的支持文件,比如app 启动后需要持久化的一些data,你的app 负责写入和移除此目录中的内容。在 iOS2.2 之后,这个目录内容不会被 ituns 备份。
<Application_Home>/tmp/
这个目录用来写入临时文件,而不是应用需要持久化的data. 当文件不再使用你的 app 应该负责删除这些内容。如果你的应用不再运行,系统会删除这个文件夹中的内容。iOS 2.1
之后这个文件夹的内容不会被 ituns 备份。
[2] 大小写敏感的文件系统
iOS 系统大小写敏感 Case-Sensitive
[3] 与 desktop 计算机共享文件
文件共享可以使你的 app 和 desktop 计算机之间共享文件。
(5) 备份和恢复 Backup and Restore
ituns 会自动处理 app 数据的备份和恢复,但你需要了解哪些目录中的内容会被备份
[1] 备份什么
你的 app 不需要为备份/恢复做什么特殊准备。在 iOS 2.2 之后,当设备连接到一个计算机并同步后,ituns 会自动增量备份所有文件,除了以下目录中的内容不会备份
- <Application_Home>/AppName.app
- <Application_Home>/Library/Caches
- <Application_Home>/tmp
尽管 ituns 会备份 app bundle 内容 (<Application_Home>/AppName.app),但是只是在第一次从 app store 上下载安装时备份,之后的连接同步不会备份这目录的内容。为了防止同步时间过长,你应该选择保存data 的目录, <Application_Home>/Documents 用来存放用户文档和 app data, 这些内容会被备份。对于临时产生的文件需要存放在 <Applicaiton_Home>/tmp 中,他不会被 ituns 备份。 如果你的 app 需要保存数据为下次 app 启动时使用,而且这些数据也不需要 ituns 备份,保存到文件<Application_Home>/Library/Caches 目录中。
(6) iOS 模拟器
你可以使用 iOS 模拟器来测试开发你的 app, 模拟器提供与设备相似的运行时环境,但不完全相同,很多限制只有在实际设备上才有,例如:不支持 paging to disk.还有 OpenGL ES 在设备和模拟器上的行为也不同。
[1] 检测硬件设备支持 Determining the available hardware support
如果你的 app 需要一个硬件支持才能运行,你需要将 UIRequiredDeviceCapabilities key 加入到 app 的 Info.plist 中,这个 key 会阻止用户将 app 安装到不支持该特性的device 上。
检查特性:
检查是否支持多任务
检查你需要配置 app 界面支持 ipad size, iphone size
检查是否有外接屏幕
检查是否有硬件级别的磁盘加密
检查是否有网络
检查是否有摄像头
检查是否支持视频录制
检查是否有 microphone
检查是否有GPS
检查是否有硬件加速计
检查当前电池水平
2.核心app 设计 the core application design
每个 iOS app 都构建在 UIKit 框架之上,有相似的架构。 系统和运行的app 之间有很多的交互,很多交互都被 UIKit 底层处理了。 UIKit 提供 hooks 给我们的代码,来实现我们需要的行为。
(1)iOS app 使用的设计模式
Model-View-Controller
MVC 将你的代码分为不同的部分。 model 定义 app的数据部分,view 定义用户界面,controller 是 model 和 view 之间的桥梁,连接并在他们之间传递数据。
Block objects
Block objects 用来封装 code 和 local stack 到一个 form 为了以后执行使用,iOS 4 之后开始支持 Block objects, 常被异步操作的回调使用。
Delegation
代理模式,是处理复杂对象而不用子类化他们的一种方式。将代码放到一个代理对象中,而不是去实现一个复杂对象的子类。复杂对象去调用代理对象的方法,从而执行你的代码。
Target-action
Controls 使用 target-action 模式来反映交互,例如用户点击按钮,control 将事件发送给你。
Manage memory model
Objective-C 使用引用计数器来决定何时释放对象的内存
Threads and concurrent programming
所有版本的iOS 都支持多线程, iOS 4 之后还支持 Grand Central Dispatch (GCD) 并发执行任务。
(2) 核心对象 the core application objects
从你的 app 被用户启动,到 app 推出, UIKit 框架管理大部分的 app 行为。例如,一个iOS app 不断从系统接收各种事件, app 必须对这些事件做出响应。 接收事件是 UIApplication 对象的工作,对事件作出响应需要你编写代码来完成。其他的部分也类似,系统对象来管理整体过程,你写的代码用来实现特定的行为。
图2-1 iOS app 中的关键对象
UIApplication object
UIApplication 对象管理 application 的 event loop, 你自己实现的 application-level 级的代码在 delegate 类中。
Application delegate 对象
Data model object
View controller object
View controller 对象管理 app 中展示界面内容,管理 view 和 data model 对象间的交互, UIViewController 是所有 view controller 对象的基类。 它对 view 提供了一些默认的支持,如 处理 device 的旋转,和其他标准的系统行为。
UIWindow Object
UIWindow 对象配合展示一个或多个 view , 大部分 iOS app 只有一个 window,app 可以更改window 中的内容,通过修改其中的 view (一般通过 view controller 对象完成)。
Views, controls, and layers
Views 和 controls 对象提供了app 中的界面内容。 A view 对象绘制页面上的一个矩形区域,并相应其中发生的事件。 控件 (controlls) 是一些响应特定事件的view, 比如:buttons, text fields, toggle switch.
可以通过子类 UIView 来实现订制的 view
(3)iOS应用程序的生命周期 The Appliation Life Cycle
iOS app 的生命周期是指发生在 app 启动和终止之间的一系列事件。 用户通过点击图标启动app , 系统显示 app 的启动画面,启动 app 是通过调用 main () 方法,之后 UIKit 框架会做很多初始化工作, 载入 app 的 main nib file, 准备好event loop.
图 2-2 是一个简化的 app 生命周期,描述了从一个 app 启动到另一个app 启动之间的过程。在app 生命周期中的关键点, UIKit 会发送消息给 delegate 对象,让 delegate 对象知道发生了什么, 在 event loop 之中,UIKit 还会将事件分发给注册的 event handler, 这些可能是 view 或 view controller
图2-2 App 生命周期
[1] main 函数 the main function
象其他的 C-based app 一样,main 函数是 iOS app 的入口,在 iOS app 中 main 的作用很少,主要是将控制交给 UIKit framework, 因此用 xcode 创建的 app 都类似如下:
- #import <UIKit/UIKit.h>
- int main(int argc, char *argv[])
- {
- NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
- int retVal = UIApplicationMain(argc, argv, nil, nil);
- [pool release];
- return retVal;
- }
UIApplicationMain 类是 main 函数的核心。
- argc 和 argv 包含了系统的启动参数, UIKit 会解析这些启动参数
- 第三个参数是制定 app 的主类,使用 nil ,UIKit 会默认使用 UIApplication 类作为主类,这是推荐用法
- 第四个参数是 app 的 delegate 类
[2] app 代理 the application delegate
监控 app 的 high-level 行为是 application delegate 类的职责。 使用 delegate 可以避免去子类化 UIKit 中的复杂对象,我们将相应代码写在代理类中,当事件发生时, UIKit 的复杂对象会将event 传递给代理类,在代理类中实现响应事件的代码。
重要 delegate 模式可以简化你的 app 开发,为你节省时间,因此是一种重要的模式。
[3] 了解app 的状态转换 Understanding an Application's States and Transitions
在 iOS 4 系统之后运行在其中的 app 可以处于以下几种状态
Not running
应用程序没有启动或者医被系统关闭
Inactive
app 在前台运行,但当前不接收 event 事件。一个 app 一般在状态转换时会处在 Inactive 状态,当用户所屏幕后 app 处于 Inactive 状态,或者系统提示用户响应一些事件时处于 Inactive 状态,比如来了电话或 SMS 消息事件。
Active
app 在前台运行,并且接受 event 事件。
Background
app 在后台并且在运行中。 大部分程序在 进入 suspended 状态之前会经过 backgound 状态,然后,一些app 会在 backgound 状态执行一段时间。也有一些应用启动后直接进入backgound 状态而不是 active 状态。 iOS 4 之后才有 background 状态。
Suspended
app 在后台并且没有执行的状态,app 处于 suspended 状态,本质上在后台的一种冰冻状态,当系统内存不足时,系统会收取 suspended app 的内存并没有通知。
状态转化时,系统会调用 delegate 对象的如下方法:
application:didFinishLaunchingWithOptions:
applicationDidBecomeActive:
applicationWillResignActive:
applicationDidEnterBackground
applicationWillEnterForeground:
applicationWillTerminate:
启动应用程序 Launching the application
在启动时, app 从 not running 状态转换到 Active 或 background 状态。app 会调用 delegate 对象的 application:didFinishLaunchingWithOptions: 方法,之后调用 applicationDidBecomeActive 或者 applicationDidEnterBackground 方法 (这依赖于应用程序是转换到 foreground 执行还是 background 执行)
图 2-3 启动应用程序进入 active 状态
方法 application:DidFinishLaunchingWithOptions: 负责启动时的大部分工作,有如下的职责:
- 初始化应用的数据结构
- 加载或者创建 app 的主window 和 view 在 portrait orientation (竖着的方向),如果设备在启动时不是在 portrait 方向,开始的时候你还是要创建在 portrait 方向的界面, 当方法 application:DidFinishLaunchingWithOptions: 返回后,application 告诉 window 翻转。
- 检查 Launching Options dictionary 中的内容
- 使用之前保存的 preference 和 状态信息,恢复 app 到上次运行时的状态
你应该让 application:DidFinishLaunchingWithOptions: 方法尽量轻量级,尽管你可能有很多的初始化工作需要在该方法中完成,但你只有大约 5 秒的时间来完成初始化并返回。但如果超时系统会终止你的 app 因为没有及时响应。使他轻量级需要将一些初始化任务异步操作或者为时间长的task 单起一个线程。尤其是那些需要 internet 连接的初始化任务。
转移到后台 move to the background
当用户按了 home 键,或者启动了另外一个 app, 前台的 app 将会先变为 inactive 状态然后进入 background 状态,这会调用代理类的 applicationWillResignActive 和 applicationDidEnterBackground: 方法。
图2-4 展示了大部分 app 进入 backgound 状态后将进入 suspended 状态,如果 app 要求再执行一段时间或者 app 声明了可以在后台执行,它会在方法return 后继续执行。
图 2-4 应用程序从前台转到后台
当 app 转到后台,你的app 核心对象会被保留,包括你的 custom objects 和 数据结构和你的 应用程序控制对象,window, views 和 layers, 系统会释放屏幕后对象的内存。
- 释放 the backing store for all core animation layers
- 释放 cache images
- 释放系统管理的一些 caches
方法 applicationDidEnterBackground 有大约 5 秒时间完成task 并返回,实际中这个方法应该尽可能快的返回,如果超时app 将会被系统中止,并释放相关内存。如果你仍然需要一些时间去执行task, 可以调用 beginBackgroundTaskWithExpirationHandler: 在后台执行一段时间,然后为长任务启动一个新的线程。
有两件事需要在方法 applicationDidEnterBackgrond: 中做:
- 当方法 applicationDidEnterBackground 返回,系统会为你的 app 做一个截图,如果你的界面有敏感数据,你需要在此方法返回前隐藏你的敏感数据。
- 保存用户数据和app 状态信息。
响应中断 Responding to interruptions
当一个临时中断发生(如电话或短信), app 会临时进入 inactive 状态,然后等待用户选择接受或忽略这个中断,如果忽略中断 app 会重新进入 active 状态,如果接受中断 app 将进入 background state。
图 2-5 处理应用程序中断
- 一个中断,如来电, 短信,或 calendar event
- 系统调用代理类的 applicationWillResignActive 方法,系统将禁掉传送 touch event 到 app.中断会暂时使你的 app 失去控制,你应该在你的代码中处理,不让中断给你的app 带来不好的用户体验。例如,如果你的 app 是一个游戏,你应该让游戏暂停,停止计数器,并让你的应用处于睡眠状态等。
- 系统会为用户显示 event alert, 供用户选择
- 如果用户忽略中断,系统调用代理类的 applicationDidBecomeActice: 方法,恢复给app 传递 touch event
- 如果用户接受中断,系统会调用代理类的 applicationDidEnterBackground 方法,你的app 会进入 background 状态,需要保存 app 的 user data 和 状态信息。 如果是 iOS4 之前的系统, 系统会调用代理类的 applicationWillTerminate: 方法。
恢复前台执行 resume foreground execution
用户重新启动一个在后台的app 时,系统先将 app 状态变为 inactive ,之后再变为 active, 系统会调用代理的 applicationWillEnterForeground: 和 applicationDidBecomeActive: 方法。 如图 2-6 所示:
图2-6 从background 转换到 froeground
[img]http://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Art/transition_bgtoact.jpg
[/img]
当app 到前台后,应该恢复app 的服务,并可以处理收到的event.
注意: 当你的app 将要转到前台,系统会发送一个通知 UIApplicaitonWillEnterForegroundNotification. 你的对象可以在接收到这个通知后重新注册自己。
当 app 处于 suspended 状态,系统会积累合并收到的event,当app 重新运行,系统将这些event 传递给app, app 根据这些event 做出相应的响应。 例如设备的方向改变了,你的app的 view controller 会自动更新 app 的方向。
响应 app 结束 responding to application termination
app 一般会转移到 backgoround 然后进入 suspended 状态,但如果满足以下你的 app 会被关闭,占用的内存被回收。
- iOS 版本是 4.0 之前
- 当前设备不支持多任务
- app 在 Info.list 文件里指定了 UIApplicationExitOnSuspend key
你的 app 在运行(在 foreground 或者 background),当结束 app 是,系统会调用代理类的 applicationWillTerminate: 方法, 你可以在该方法中执行一些清理工作。也在这个方法中保存 user data 和 app 状态信息,以便下次启动时进入这个状态。你必须在 5 秒内完成这些工作并返回,否则系统会强制关闭你的 app ,并清除内存。 如果你的 app 处于suspended 状态,系统不会调用 applicationWillTerminate: 方法。
使用 iOS4 以后的系统,你也需要为app 的结束做准备,用户可以显示的通过Mulititasking UI 来结束 app, 如果系统内存紧张,系统也会清除一些app 来获得内存空间,如果你的 app 在 supseneded 状态,系统会在没有提示的情况下回收你app 的内存。如果你的app 在 background 运行,系统会调用 applicationWillTerminate 方法,你的 app 不能在这个方法中要求更多的执行时间。
多任务 Multitasking
在 iOS4 之后, 多个app 可以在内存中同时运行。只有一个 app 在前台,其他的app 在background 中。 app 必须考虑在 foregrond 和 background 之间的转换。
为支持多任务app 需满足如下条件:
- (必须满足) 当状态变化时 app 需要作出恰当的响应。app 需要监听这些状态变化,为了保存app 状态信息和剪裁 app 在 background 和 foreground 运行时的行为。如果没有处理状态变化可能会导致 app 丢失数据或者不正确的行为。
- (必须满足) 遵循进入 background 的守则,这些守则会帮助你的app 正确进入backgournd 状态,和在某些时候结束。
- (建议) 你的app 注册监听系统的所有状态变化notice. 当app 处于 supended 状态时,系统会将 notice 保存在队列中,当app 恢复运行后,将notice 再传递给 app,这个app 可以做相应的平稳变化。
- (可选) 如果你的app 需要在backgorund 状态运行,你的app 需要请求在backgournd 中继续执行的 permission.
开发一个支持多任务执行的app Being a Responsible, Multitasking-Aware Application
在前台运行的app 对系统资源和硬件有优先权,因此 app 在前后台状态转换时需要修改它们的行为。特别是,当app 转到后台执行需要遵循以下守则:
- 不要在你的代码中执行任何 OpenGL ES 调用 , 当app 在后台运行时,你不能创建 EAGLContext 对象或者调用 OpenGL ES 绘制命令。这些调用会导致你的app 立即被终止。
- 在suspended 状态之前取消所有 Bonjour-related 服务, 当你的app 进入到后台,在它到suspended 状态之前, 应该取消在 Bonjour 上的注册,并关闭相关的socket 监听和网络服务。一个在 supspended 状态的 app 不能响应到来的 service 请求。关闭和这些服务可以阻止这写请求试图到达但实际上不能的情况。 如果你自己没有取消 Bonjour 服务系统会在app suspended 状态时关闭这些服务
- 准备处理 socket 链接失败 当app 进入 suspended 状态系统可能会关闭它的socket 连接。你的 socket 相关代码需要处理这些连接失败情况,例如失去连接,或者网络变化,这样就不会产生什么奇怪的问题。这样当你的app 恢复运行,如果遇到一个 scokcet 连接是败,简单的重建连接就可以了。
- 进入background 之前保存你的 app 状态信息 在系统内存紧张的情况下。后台的app 可能会被清除内存来缓解内存紧张。 suspended 状态的app 会被首先清除,而且清除前系统不会发出任何提示。因此,在进入background 之前 app 需要保存足够的状态信息,已被重新运行。
- 进入background 之前释放任何不必要的内存 如果你的app 在内存中有个大的cache 对象 (尤其是图片),在app 进入background 状态之前你应该释放 cache 对象占用的内存。在低内存的情况下,系统会选择占用内存大的后台app 先释放,释放不必要的cache 内存一方面可以缓解系统的内存压力,另一方面可以使你的app 比较靠后的被系统释放。
- 在app 进入 suspended 状态前停止使用系统共享资源 如果app 使用了地址簿,日历等系统共享资源,应该在app 进入suspended 状态前取消这些资源的使用。前台app 对这些共享资源的使用优先级高,如果你的 app 在 suspended 状态下被检查到使用了共享资源,它将会被关闭。
- 避免更新你的 windows 和 views 当app 在后台,app 的 windows 和 views 是不可见的。所以不要试图更新他们。尽管更新在后台app 的 windows 和 views 不会导致你的app 被关闭,但这些更新会被推迟到你的app 进入前台后才会执行。
- 响应外部的连接和断开连接提示 当app 与外部的 accessory 通讯,app 转入background 时系统会发送断开连接提示,app 需要注册监听这个提示,当收到提示后断开与外部accessory 的连接,当app 重新回到前台执行,系统会发送一个连接提示,app 监听这个提示来重新建立与外部 accessory 的连接。
- 当app 进入backgound 状态时清除 active alert 资源 为了保持app 切换时的上下文,当app 进入backgourd 时系统不会自动清除 action sheet (UIActionSheet) 和 alert view (UIAlertView), 需要你自己在app 进入background 前做相关清理。
- app 进入background 前从view 中移除敏感信息 在app 进入background 之前,系统会为app 的主窗口做一个快照截屏。所以在方法 applicationDidEnterBackground: 中你应该隐藏界面上的敏感信息。
- 当后台运行时app 做尽量少的工作 系统分配给后台app 的执行时间要比前台的app 少的多,如果你的app 在后台播放音乐或者检测位置变化。你应该尽量减少不必要的操作。后台app 如果占用过多的执行时间可能会被系统关闭。