Iphone开发(1)

来源:互联网 发布:切削参数计算软件 编辑:程序博客网 时间:2024/06/05 20:05

应用程序的生命周期

应用程序的生命周期是由发生在程序启动到终止期间的一序列事件构成的。在iPhone OS中,用户可以通过轻点Home屏幕上的图标来启动应用程序。在轻点图标之后的不久,系统就会显示一个过渡图形,然后调用相应的main函数来启动应用程序。从这个点之后,大量的初始化工作就会交给UIKit,由它装载应用程序的用户界面和准备事件循环。在事件循环过程中,UIKit会将事件分发给您的定制对象及响应应用程序发出的命令。当用户进行退出应用程序的操作时,UIKit会通知应用程序,并开始应用程序的终止过程。

图1-1显示了一个简化了的iPhone应用程序生命周期。这个框图展示了发生在应用程序启动到退出过程中的事件序列。在应用程序初始化和终止的时候,UIKit会向应用程序委托对象发送特定的消息,使其知道正在发生的事件。在事件循环中,UIKit将事件派发给应用程序的定制事件处理器。有关初始化和终止事件的如何处理的信息,将在随后的“初始化和终止”部分进行讨论;事件处理的过程则在“事件处理周期”部分介绍,在后面的章节也还有更为详细的讨论。

图1-1  应用程序的生命周期

Application life cycle

主函数

在iPhone的应用程序中,main函数仅在最小程度上被使用,应用程序运行所需的大多数实际工作由UIApplicationMain函数来处理。因此,当您在Xcode中开始一个新的应用程序工程时,每个工程模板都会提供一个main函数的标准实现,该实现和“处理关键的应用程序任务”部分提供的实现是一样的。main例程只做三件事:创建一个自动释放池,调用UIApplicationMain函数,以及使用自动释放池。除了少数的例外,您永远不应该改变这个函数的实现。

程序清单1-1  iPhone应用程序的main函数

#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;
}

请注意:自动释放池用于内存管理,它是Cocoa的一种机制,用于延缓释放具有一定功能的代码块中创建的对象。有关自动释放池的更多信息,请参见Cocoa内存管理编程指南;如果需要了解与自动释放池有关的具体内存管理规则,则请参见“恰当地分配内存”部分。

程序清单的核心代码是UIApplicationMain函数,它接收四个参数,并将它们用于初始化应用程序。传递给该函数的缺省值并不需要修改,但是它们对于应用程序启动的作用还是值得解释一下。除了传给main函数的argcargv之外,该函数还需要两个字符串参数,用于标识应用程序的首要类(即应用程序对象所属的类)和应用程序委托类。如果首要类字符串的值为nil, UIKit就缺省使用UIApplication类;如果应用程序委托类为nil,UIKit就会将应用程序主nib文件(针对通过Xcode模板创建的应用程序)中的某个对象假定为应用程序的委托对象。如果您将这些参数设置为非nil值,则在应用程序启动时,UIApplicationMain函数会创建一个与传入值相对应的类实例,并将它用于既定的目的。因此,如果您的应用程序使用了UIApplication类的定制子类(这种做法是不推荐的,但确实是可能的),就需要在第三个参数指定该定制类的类名。

应用程序的委托

监控应用程序的高级行为是应用程序委托对象的责任,而应用程序委托对象是您提供的定制类实例。委托是一种避免对复杂的UIKit对象(比如缺省的UIApplication对象)进行子类化的机制。在这种机制下,您可以不进行子类化和方法重载,而是将自己的定制代码放到委托对象中,从而避免对复杂对象进行修改。当您感兴趣的事件发生时,复杂对象会将消息发送给您定制的委托对象。您可以通过这种“挂钩”执行自己的定制代码,实现需要的行为。

重要提示:委托模式的目的是使您在创建应用程序的时候省时省力,因此是非常重要的设计模式。如果您需要概要了解iPhone应用程序中使用的重要设计模式,请参见“基本设计模式”部分;如果需要对委托和其它UIKit设计模式的详细描述,则请参见Cocoa基本原理指南部分。

 

应用程序的委托对象负责处理几个关键的系统消息。每个iPhone应用程序都必须有应用程序委托对象,它可以是您希望的任何类的实例,但需要遵循UIApplicationDelegate协议,该协议的方法定义了应用程序生命周期中的某些挂钩,您可以通过这些方法来实现定制的行为。虽然您不需要实现所有的方法,但是每个应用程序委托都应该实现“处理关键的应用程序任务”部分中描述的方法。

有关UIApplicationDelegate协议方法的更多信息请参见UIApplicationDelegate协议参考

主Nib文件

初始化的另一个任务是装载应用程序的主nib文件。如果应用程序的信息属性列表(Info.plist)文件中含有NSMainNibFile键,则作为初始化过程的一个部分,UIApplication对象会装载该键指定的nib文件。主nib文件是唯一一个自动装载的nib文件,其它的nib文件可以在稍后根据需要进行装载。

Nib文件是基于磁盘的资源文件,用于存储一或多个对象的快照。iPhone应用程序的主nib文件通常包含一个窗口对象和一个应用程序委托对象,还可能包含一个或多个管理窗口的其它重要对象。装载一个nib文件会使该文件中的对象被重新构造,从而将每个对象的磁盘表示转化为应用程序可以操作的内存对象。从nib文件中装载的对象和通过编程方式创建的对象之间没有区别。然而,对于用户界面而言,以图形的方式(使用Interface Builder程序)创建与用户界面相关联的对象并将它们存储在nib文件中通常比以编程的方式进行创建更加方便。

有关nib文件及其在iPhone应用程序中如何使用的更多信息,请参见“Nib文件”部分,有关如何为应用程序指定主nib文件的信息则请参见“信息属性列表”部分。

事件处理周期

在应用程序初始化之后,UIApplicationMain函数就会启动管理应用程序事件和描画周期的基础组件,如图1-2所示。在用户和设备进行交互的时候,iPhone OS会检测触摸事件,并将事件放入应用程序的事件队列。然后,UIApplication对象的事件处理设施会从队列的上部逐个取出事件,将它分发到最适合对其进行处理的对象。举例来说,在一个按键上发生的触摸事件会被分发到对应的按键对象。事件也可以被分发给控制器对象和应用程序中不直接负责处理触摸事件的其它对象。

图1-2  事件和描画周期

The event and drawing cycle

在iPhone OS的多点触摸事件模型中,触摸数据被封装在事件对象(UIEvent)中。为了跟踪触摸动作,事件对象中包含一些触摸对象(UITouch),每个触摸对象都对应于一个正在触摸屏幕的手指。当用户把手指放在屏幕上,然后四处移动,并最终离开屏幕的时候,系统通过对应的触摸对象报告每个手指的变化。

在启动一个应用程序时,系统会为该程序创建一个进程和一个单一的线程。这个初始线程成为应用程序的主线程,UIApplication对象正是在这个线程中建立主运行循环及配置应用程序的事件处理代码。图1-3显示了事件处理代码和主运行循环的关系。系统发送的触摸事件会在队列中等待,直到被应用程序的主运行循环处理

图1-3  在主运行循环中处理事件

Processing events in the main run loop

请注意:运行循环负责监视指定执行线程的输入源。当输入源有数据需要处理的时候,运行循环就唤醒相应的线程,并将控制权交给输入源的处理器代码。处理器在完成任务后将控制权交回运行循环,然后,运行循环就处理下一个事件。如果没有其它事件,运行循环会使线程进入休眠状态。您可以通过Foundation框架的NSRunLoop类来安装自己的输入源,包括端口和定时器。更多有关NSRunLoop和运行循环的一般性讨论,请参见线程编程指南

UIApplication对象用一个处理触摸事件的输入源来配置主运行循环,使触摸事件可以被派发到恰当的响应者对象。响应者对象是继承自UIResponder类的对象,它实现了一或多个事件方法,以处理触摸事件不同阶段发生的事件。应用程序的响应者对象包括UIApplicationUIWindowUIView、及所有UIView子类的实例。应用程序通常将事件派发给代表应用程序主窗口的UIWindow对象,然后由窗口对象将事件传送给它的第一响应者,通常是发生触摸事件的视图对象(UIView)。

除了定义事件处理方法之外,UIResponder类还定义了响应者链的编程结构。响应者链是为实现Cocoa协作事件处理而设计的机制,它由应用程序中一组链接在一起的响应者对象组成,通常以第一响应者作为链的开始。当发生某个事件时,如果第一响应者对象不能处理,就将它传递给响应者链中的下一个对象。消息继续在链中传递—从底层的响应者对象到诸如窗口、应用程序、和应用程序委托这样的高级响应者对象—直到事件被处理。如果事件最终没有被处理,就会被丢弃。

进行事件处理的响应者对象可能发起一系列程序动作,结果导致应用程序重画全部或部分用户界面(也可能导致其它结果,比如播放一个声音)。举例来说,一个控键对象(也就是一个UIControl的子类对象)在处理事件时向另一个对象(通常是控制器对象,负责管理当前活动的视图集合)发送动作消息。在处理这个动作消息时,控制器可能以某种方式改变用户界面或者视图的位置,而这又要求某些视图对自身进行重画。如果这种情况发生,则视图和图形基础组件会接管控制权,尽可能以最有效的方式处理必要的重画事件。

更多有关事件、响应者、和如何在定制对象中处理事件的信息,请参见“事件处理”部分;更多有关窗口及视图如何与事件处理机制相结合的信息,请参见“视图交互模型”部分;有关图形组件及视图如何被更新的更多信息,则请参见“视图描画周期”部分。

基本设计模式

UIKit框架的设计结合了很多在Mac OS X Cocoa应用程序中使用的设计模式。理解这些设计模式对于创建iPhone应用程序是很关键的,我们值得为此花上几分钟时间。下面部分将简要概述这些设计模式。

表1-1  iPhone应用程序使用的设计模式

设计模式

描述

模型-视图-控制器

模型-视图-控制器(MVC)模式将您的代码分割为几个独立的部分。模型部分定义应用程序的数据引擎,负责维护数据的完整性;视图部分定义应用程序的用户界面,对显示在用户界面上的数据出处则没有清楚的认识;控制器部分则充当模型和控制器的桥梁,帮助实现数据和显示的更新。

委托

委托模式可以对复杂对象进行修改而不需要子类化。与子类化不同的是,您可以照常使用复杂对象,而将对其行为进行修改的定制代码放在另一个对象中,这个对象就称为委托对象。复杂对象需要在预先定义好的时点上调用委托对象的方法,使其有机会运行定制代码。

目标-动作

控件通过目标-动作模式将用户的交互通知给您的应用程序。当用户以预先定义好的方式(比如轻点一个按键)进行交互时,控件就会将消息(动作)发送给您指定的对象(目标)。接收到动作消息后,目标对象就会以恰当的方式进行响应(比如在按动按键时更新应用程序的状态)。

委托内存模型

Objective-C使用引用计数模式来确定什么时候应该释放内存中的对象。当一个对象刚刚被创建时,它的引用计数是1。然后,其它对象可以通过该对象的retainrelease、或autorelease方法来增加或减少引用计数。当对象的引用计数变为0时,Objective-C运行环境会调用对象的清理例程,然后解除分配该对象。

原创粉丝点击