App Programming Guide for iOS -> 应用生命周期

应用是自定义代码和系统框架之间复杂的交互结果。系统框架提供所有应用运行所需的基础架构,你提供自定义框架及你想要的应用观感所需的代码。想要做到这样的效果,理解一点关于iOS基础框架及其工作原理是很有帮助的。

iOS框架依赖于设计模式,例如MVC和委托。理解这些设计模式对于成功创建应用至关重要。它也有助于熟悉OC语言及其功能。如果你是iOS编程新手,请先阅读Start Developing iOS Apps (Swift),来了解iOS应用和OC语言。

Main函数

每个C基础的应用的入口都是main函数,iOS应用也不例外。不同之处在于,iOS应用不需要你亲自写main函数。相反,Xcode创建了这个函数作为你的基础项目的一部分。代码清单2-1显示了这个函数的一个例子。除了少数例外,你不需要改变Xcode提供的这个main函数的实现。

代码清单2-1 iOS应用的main函数

#import <UIKit/UIKit.h>

#import "AppDelegate.h"

 

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

{

    @autoreleasepool {

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

    }

}

Main函数唯一提及的事是,它的工作是把控制权交给UIKit框架。UIApplicationMain函数通过创建应用的核心对象来处理这个过程,从可用的storyboard文件加载应用的用户界面、调用你的自定义代码使你有机会进行一些初始化设置、并且让应用的运行时循环动起来。你需要提供的仅仅是storyboard文件和自定义初始化代码。

一个应用的结构

在启动期间,UIApplicationMain函数设置了介个关键对象,并启动了应用运行。每个iOS应用的核心是UIApplication对象,它的工作就是促使系统和应用中的其他对象进行交互。图2-1展示了大多数应用中常见的对象,同时,表2-1罗列了每个对象所扮演的角色。首先要注意iOS应用使用了MVC结构。这种设计模式将数据和业务逻辑从数据的可视化呈现中分离出来。这种结构对于创建适配各种屏幕的设备的应用至关重要。

图2-1 iOS应用中的关键对象

表2-1 iOS应用中对象的角色

对象 描述
UIApplication 对象 UIApplication对象管理事件循环以及其他高级的应用行为。它会向它的委托(delegate)通报关键的应用转换以及一些特定事件(例如传入推送通知),这个委托是一个你定义的自定义对象。UIApplication没有子类,它的对象类型只能是UIApplication自身。
App delegate 对象 App delegate 对象是自定义代码的核心。这个对象和UIApplication对象系统工作来处理应用的初始化、状态转换、以及很多高级的应用事件。这个对象也是唯一能保证能出现在每个应用中的对象,所以它经常被用于设置应用的初始数据结构。
文档和数据模型对象 数据模型对象存储你的应用的内容,并且只用于你的应用。例如,银行应用可能存储包含金融交易的数据,而绘画应用或许存储图片对象或存储用于创建一个图像的绘制命令的顺序。(对于后一种情况,一个图片对象依然是数据对象,因为它是图像数据的容器。)
应用也能使用文档(document,自定义UIDocument的子类)对象来管理它们的数据模型的部分或全部对象。文档对象不是必须的,但是它提供一个方便的方式来对属于单个文件或者文件包的数据进行分组。有关文档更多的信息,参见 Document-Based App Programming Guide for iOS。
视图控制器对象 视图控制器对象管理应用的内容在屏幕上的呈现。一个视图控制器管理一个单一的视图和它的子视图集合。当显示的时候,视图控制器通过把它的视图安装到应用的window中以便显示。
UIViewController类是所有视图控制器对象的基类。它提供默认的功能来加载视图、呈现它们、旋转它们以响应设备的旋转、以及其他几种标准的系统行为。UIKit和其他框架定义额外的视图控制器类来实现标准系统接口,例如图片拾取器(image picker)、标签栏接口(tab bar interface)、以及导航接口(navigation interface)。
关于如何使用视图控制器的详细信息,参见View Controller Programming Guide for iOS。
UIWindow 对象 UIWindow对象协调在屏幕上的一个或多个视图的外观。大多数的应用只有一个窗口,它在主屏幕上显示内容,但是有的应用可能有附加窗口用来在外部显示器上显示内容。
为了改变应用的内容,你使用视图控制器来改变在相应窗口中的视图呈现。你永远不用替换窗口本身。
除了托管视图之外,窗口还可以使用UIApplication对象来传递事件给视图和视图控制器。
视图对象、控件对象、层对象 视图和空间提供应用内容的视觉化外观。视图是一个对象,它把内容绘制在一个指定的矩形区域中,并响应在这个区域中的事件。控件是视图的一种特定类型,它负责实现一些熟悉的交互界面对象,例如按钮、文本字段(text fields)、以及切换开关(switch)。
UIKit框架提供标准的视图来呈现很多不同类型的内容。你也能通过直接子类化UIView(或者它的后代)定义自己的自定义视图。
除了包含视图和控件之外,应用也能把Core Animation图层(layer)合并到它们的视图和控件层次结构中。图层对象实际上是呈现的可视内容的数据对象。视图使用集合在屏幕后面的图层对象来渲染它们的内容。你也能添加自定义的图层对象到你的界面,来实现复杂的动画以及复杂的视觉效果的其他类型。

iOS 应用之间的区别在于它管理的数据(以及相应的业务逻辑)以及呈现这些数据的方式。UIKit对象的大多数交互行为不会定义你的应用,但是会帮助你有话它的行为。例如,应用的委托方法让你知道应用何时改变了状态,以便你的自定义代码的恰当地响应。

主运行循环

应用的主运行循环处理所有与用户相关的事件。UIApplication对象在启动的时候设置主运行循环,并使用它来处理事件,并处理基于视图的界面更新。顾名思义,主运行循环在应用的主线程上运行。此行为确保用户相关的事件会依照它们被接收的顺序依次处理。

图2-2展示了主运行循环的结构,以及用户事件是如何导致应用动作的。当用户与设备交互时,与这些交互相关的事件由系统生成,并经由UIKit设置的特定端口传递给应用。事件在应用内部被排序,并且逐个分派到主运行循环执行。UIApplication对象时接收事件的第一个对象,并决定需要做什么。触摸事件通常被分派到主窗口对象,主窗口对象又把它分派给触摸发生的视图。其他事件可能会通过各种应用对象而略有不同。

图2-2 在主运行循环处理事件

Processing events in the main run loop

在iOS应用中,很多类型的事件可以被传送。最常见的已在表2-2中列出。很多这些事件类型使用应用的主运行循环,但是也有一些不是。一些事件被发送到一个委托对象或者被传递给一个你提供的block。关于如何处理大多数事件的类型的信息——包括触摸、遥控器、运动、加速计、陀螺仪等事件——参见Event Handling Guide for UIKit Apps。

表2-2 iOS应用常见事件类型

事件类型 传递到... 注意
触摸 事件发生的视图对象 视图时响应者对象。任何在这个视图中没有处理的事件都被发送到响应者链中进行处理。
遥控器
摇动运动事件
第一响应者对象 遥控器事件用于控制媒体播放,由耳机和其他附件产生。
加速计
磁力计
陀螺仪
你指定的对象 与加速计、磁力计、陀螺仪等硬件相关的事件被传颂到你指定的对象。
位置 你指定的对象 你使用 Core Location框架来注册接收位置事件。更多关于使用Core Location的信息,参见Location and Maps Programming Guide。
重绘 需要更新的视图 重绘事件不涉及事件对象,但是为了重绘视图自身,该事件会简单的调用视图。iOS绘图层次结构在 Drawing and Printing Guide for iOS中描述。

一些事件,例如触摸和遥控器事件,都是通过应用的响应者对象处理的。响应者对象在应用中随处可见。(UIApplication对象、视图对象、视图控制器对象都是响应者对象的例子。如果需要处理一个事件,绝大多数事件的目标是一个特定的响应者对象,但是它也能被传递到其他响应者对象(沿着响应者链)。例如,视图没有处理一个事件,这个视图会把这个事件传递给它的父视图或者它的视图控制器。

在控件(例如按钮)中发生的触摸事件与发生在很多其他类型的视图上的触摸事件比起来,处理上会有所不同。控件的可能的交互数量一般都有限定,这些交互被打包进动作消息然后发送给合适的目标对象。这种目标动作(target-action)设计模式可以让控件触发应用中的自定义代码执行变得很容易。

应用的执行状态

在任何给定的瞬间,应用必定处于表2-3罗列的状态中的一种。系统把应用从一个状态移动到另一个状态,以响应整个系统中发生的动作。例如,当用户点击Home键的时候、有电话呼入、或者发生其他任何中断事件,当前运行的应用会响应这些事件而改变状态。图2-3展示了当应用从一个状态转到另一个状态时所经历的路径。

表2-3 应用状态

状态 描述
不运行 应用没有被启动或者曾经运行但是被系统终止。
非活跃 应用正在前台运行,但是当前没有接收事件(或许正在执行其他代码)。应用通常只在转换到其他状态时的短暂时间处于这种状态。
活跃 应用在前台执行,并且接受事件。这时前台的应用的通常状态。
后台 应用在后台执行代码。大多数应用在它们被挂起的时候会短暂停留在此状态。但是,如果应用请求了额外的执行时间,那么就可以保持这个状态一段时间。另外,在后台直接启动的应用会进入这个状态而不是非活跃(inactive)状态。关于如何在后台时执行代码,参见Background Execution。
挂起 应用在后台,但是它不执行代码。系统会无声无息地自动把应用移入这个状态。当挂起时,应用在内存中保留,但是不执行任何代码。
当出现低内存条件时,系统会悄无声息的清除挂起的应用,从而为前台应用提供更多空间。

图2-3 在iOS应用中的状态改变

大多数状态转换伴随着应用委托对象方法的相应调用。这些方法是一个以合适的方式响应状态改变的机会。这些方法及方法的使用方式摘要罗列如下。

  • application:willFinishLaunchingWithOptions:——这个方法是应用启动时第一个执行代码的机会。
  • application:didFinishLaunchingWithOptions:——这个方法允许你在应用显示给用户之前执行任何最终的初始化。
  • applicationDidBecomeActive:——让应用知道它要变成前台应用。用这个方法做最后一刻的准备。
  • applicationWillResignActive:——让你知道应用正在从前台应用往外转换。使用这个方法来把应用置于休眠状态。
  • applicationDidEnterBackground:——让你知道应用现在正在后台运行并且可能在任何时刻被挂起。
  • applicationWillEnterForeground:——让你知道应用正在移出后台回到前台,但是现在还没有到达活跃状态。
  • applicationWillTerminate:——让你知道应用正在被终止。如果应用已被挂起那这个方法不会被调用。

应用终止

应用必须为随时发生的终止做好准备,并应该立刻保存数据或者执行其他关键的任务。系统发起的终止是应用生命周期的正常部分。系统通常终止应用,以便回收内存,并给用户启动的其他应用提供空间,但是系统也可能在应用发生错误或者没有及时响应事件的时候终止它。

挂起应用在它们被终止的时候不会收到任何通知;系统杀死进程并收回相关的内存。如果应用现在正在后台运行没有被挂起,系统会在种植之前调用它的委托方法applicationWillTerminate: 。在设备重启的时候系统不会调用这个方法。

除了系统终止你的应用之外,用户也可以使用多任务UI来主动的终止你的应用。用户发起的终止与终止挂起应用的效果是一样的。应用的进程被杀死且不会有通知发送给应用。

线程和并发

系统创建应用的主线程,如有必要你可以创建额外的线程来执行其他任务。对于iOS应用,首选技术是使用Grand Central Dispatch(GCD)、操作对象(operation object)、以及其他异步编程接口,而不是自己创建并管理线程。像GCD这样的技术让你定义你想做的事情以及做这些事情的顺序,但让系统决定如何在可用的CPU上执行该工作。让系统处理线程的管理可以简化你必须写的代码,使得确保代码的正确性变得容易,并且提供了更好的整体性能。

当思考关于线程和并发的时候,请考虑以下几点:

  • 涉及视图、核心动画、以及其他UIKit类的工作,通常都发生在应用的主线程。虽也有一些例外——例如,基于图片的操作通常发生在后台线程——但当有疑问时,要假定这项工作需要在主线程中发生。
  • 长时任务(或潜在的长时任务)应该总是在后台线程中执行。任何涉及网络访问、文件访问、或者大量数据处理的任务都应该使用GCD或者操作对象进行异步执行。
  • 在启动时,尽可能的把任务从主线程移出。在启动时,应用应该尽可能快的设置用户界面。只有有助于设置用户界面的任务才应该在主线程上运行。所有任务都应该异步执行,一旦它们有结果就呈现个用户。

更多关于使用GCD和操作对象执行任务的信息,参见Concurrency Programming Guide。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容