Creating an iPhone Application
[中文译稿]
前言
在读下面的章节之前请首先掌握Objectv-C的一些基本知识. 其次, 请务必到
Apple dev主页上去下载MoveMe的Sample代码,因为本文都是围绕该Sample来进
行描述.
因为原文中关于Objectv-C部分的章节内容能够很容易的在网上搜索到,因此本
译稿没有包含这部分内容.
Initializing the MoveMe Application
每一个iPhone应用的入口都是main函数。值得庆幸的是,当你使用Xcode的
iPhone模板创建一个新工程时,你不需要自己来实现这个函数。工程模板已经
包含了启动应用程序的所有代码。
Listing 1 展示了MoveMe应用程序的main函数的实现。main函数位于工程的
main.m文件中。每一个你创建的应用程序都会含有一个类似的main函数。该函
数主要做两件事。首先,它创建应用程序的top-level autorelease pool,作用是
Objective-C对象可以自由使用自己的autorelease方法来回收内存。其次,调用
UIApplicationMain函数来创建MoveMe应用的主要对象,初始化这些对象,并
且开始event-processing循环。只有当该循环退出时应用程序才会从该函数返
回。
Listing 1 使用提供的main函数
Creating the Application Delegate
大部分Xcode工程模板都会自动地为你创建Delegate对象,提供一个基本类,
你可以在当你需要定义自己的应用程序行为的时候修改它。在MoveMe工程中,
应用程序delegate类的定义在MoveMeAppDelegate.h文件中,实现位于
MoveMeAppDelegate.m文件中。
应用程序的delegate对象和标准UIApplication对象以串行方式工作,响应应用
程序中的状态改变。应用程序对象负责大部分工作,但是delegate负责几个主
要的工作:
- 建立应用程序窗口并且初始化用户界面。
- 为所有自定义数据引擎提供额外的初始化工作。
- 响应中断,诸如电话呼入或接收到短信之类。
- 通过释放额外的内存来响应内存不足的情况。
- 当系统需要应用程序退出的时候负责退出应用程序。
- 处理从外部传入应用程序的URLs。
int main(int argc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc]
init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
return retVal;
}
- 响应设备的定向改变。
在启动时,最关心的是delegate对象的创建和将应用程序窗口展示给用户,该
处理的细节在“Creating the Application Window”中描述。当应用退出时,
delegate对象需要顺序的执行应用的shutdown操作,并保存所有下次启动时需
要的状态信息。
工程中的主要nib文件用于连接应用程序对象和创建的delegate对象。一个nib文
件其实就是一个资源文件,它包含了一套freeze-dried对象。你可以使用
Interface Builder程序来创建和编辑nib文件,指定你想要的对象在运行时装载
进你的应用程序。当你的应用程序在运行时装载nib文件时,nib-loading代码会
自动地在该nib文件里重新创建对象,正确地配制它们并且使其有效。
在MoveMe应用程序中,主要的nib文件包含一个MoveMeAppDelegate类的实
例,连接该对象和标准UIApplication对象。
双击MainWindow.xib文件打开该nib文件。选择File’s Owner图标(它表示
UIApplication对象)并且打开connections inspector(见Figure3),可以看到
应用和delegate的连接。File’s Owner对象可以被认为是“proxy”对象,因为
它在程序运行时充当被创建对象的一个占位符。换句话说,
MoveMeAppDelegate是在nib-loading过程中被创建的。
Figure 3 The application delegate
Creating the Application Window
每一个应用都要负责创建一个覆盖全屏的窗口,并且用内容填充该窗口。图形
应用在iPhone OS上运行时不允许与其它应用并行运行。实际上,除了内核以及
少数底层系统后台程序之外,你的应用在启动之后是唯一运行的程序。而且,
你的应用应该不能多于一个窗口——一个UIWindow类的实例。在某些情况下,
你在需要改变用户界面的时候,你可以通过改变视图显示的方式来实现。
窗口为你的用户界面进行表面描画工作,但是视图对象提供实际的内容。一个
视图对象就是一个UIView类的实例,它负责描画内容并且响应内容的交互。
iPhone OS定义了标准的视图来表示诸如表,按钮,文本框等内容,以及其它类
型的交互控制。你可以添加上述任意的视图到你的窗口,或者你也可以通过
UIView的子类来自定义视图,自己实现一些自定义的描画和事件处理代码。
MoveMe应用程序定义了两个这样的视图——MoveMeView和
PlacardViewclasses——用于显示应用的接口和处理用户的交互。
在运行时,为了尽快地创建应用程序窗口并显示一些初始化的内容。所以,
Window对象并不是存储于MainWindow.xib nib文件中。当应用程序启动并准备
开始处理事件时,UIApplication对象发送给delegate对象一个
applicationDidFinishLaunching消息。该消息提示delegate将内容放进窗口并
且执行其它需要的初始化工作。
在MoveMe应用程序中,delegate的applicationDidFinishLaunching方法做如下
的工作。
1.创建视图控制器实例来管理窗口内容视图。
2.使用需要进行内容管理的nib文件(MoveMeView.xib)的名字初始化视
图控制器(MoveMeView.xib文件包含了在窗口中需要被显示的视图)。
3.添加控制器的视图作为窗口的子视图。
4.显示窗口。
Listing 2展示了MoveMe应用的applicationDidFinishLaunching方法,它被定
义在应用程序delegete对象的实现文件——MoveMeAppDelegate.m中。该方法为
窗口创建主要的内容视图并且使窗口有效。显示中的窗口能够让系统知道你的
应用程序已经准备开始处理事件了。
Listing 2 Creating the content view
注意:你可以除了使用applicationDidFinishLaunching方法建立你的应用程序
用户界面之外还可以执行其它的任务。例如,你可以使用它初始化需要的数据
结构,或者返回到应用程序上次退出时的状态。在应用程序生命周期的早期要
特别注意别包含太多的任务,尤其是那些可以在后期容易执行的任务。在启动
时执行太多的任务会使你的应用程序在展示给用户时反映迟钝。
尽管前面的代码创建了窗口的背景视图并且显示了窗口,但你有没有注意到在
前面的代码中创建了PlacardView类用于显示Welcome按钮。 MoveMeView对象在
从nib文件被装载的过程中, PlacardView类已经被隐含的实例化了 。
MoveMeView对象使用initWithCoder方法进行初始化,该方法接着调用
setUpPlacardView方法(参见Listing 3)来创建和配置PlacardView对象。
PlacardView对象被配置为MoveMeView对象的子视图。这层关系导致了Welcome
按钮被显示在应用程序背景的上面,并且允许MoveMeView对象处理Welcome按钮
上的事件。
Listing 3 Creating the placard view
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
/*
Set up a view controller to manage the MoveMeView.
Since the view controller has no custom behavior in this
application, just use an instance of UIViewController.
*/
UIViewController *aViewController = [[UIViewController alloc]
initWithNibName:@"MoveMeView" bundle:[NSBundle mainBundle]];
self.viewController = aViewController;
[aViewController release];
// Add the view controller's view as a subview of the window
UIView *controllersView = [viewController view];
[window addSubview:controllersView];
[window makeKeyAndVisible];
}
- (void)setUpPlacardView {
// Create the placard view -- its init method calculates its
frame based on its image
PlacardView *aPlacardView = [[PlacardView alloc] init];
self.placardView = aPlacardView;
[aPlacardView release];
placardView.center = self.center;
[self addSubview:placardView];
}