要理解我们将对项目所做的自定义,最好要知道从哪里开始入手。新建的空项目是可以运行的,尽管其运行效果显然并不是非常有趣。花点时间运行一下该应用程序,运行效果如图2-6所示。接下来将删除状态栏并探讨在项目中开始添加自定义代码的最佳位置。
在图2-6中,我们看到了新建的通用应用程序运行于iPhone模拟器的效果。要在iPad模拟器上运行该应用程序,从Scheme下拉菜单中选择iPad Simulator,该下拉菜单在Xcode中Stop按钮的右侧。正如我们所看到的,该应用程序是空的,只有一个灰色背景。另外需要注意的是,该应用程序的顶部显示有状态栏。虽然有很多合理的理由在应用程序中包含状态栏,但许多游戏的开发人员仍希望删除掉状态栏,以创造一个更令人感到身临其境的游戏空间。要删除状态栏,点击项目导航器(Xcode左侧树形结构)中的根元素。选择Targets,然后点击右侧的Info选项卡。图2-7显示了正确屏幕。
图2-7 配置状态栏
看到如图2-7所示的视图后,右击最上面的元素(A)并选择Add Row。这将在项目的列表中添加一个新元素。需要将键值设置为“Status bar is initially hidden”并将其值设置为“Yes”。在此所做的操作其实是在编辑Supporting Files分组下的plist文件。Xcode只是为你提供了一个很好的界面来编辑此配置文件。
提示:
导航至Supporting Files分组下以info.plist结尾的文件。右击该文件并选择Open As | Source Code,以显示该plist源文件的内容。注意其中的键值是以常量形式保存的,而不像在Info编辑器中使用的可供人们阅读的文本。
再次运行该应用程序时,状态栏已经被删除了,如图2-8所示。
图2-8 没有状态栏的默认应用程序
至此,我们已经探讨了一个自定义应用程序的简单方式。现在是时候研究iOS应用程序的组成方式了,从而在添加我们自己的功能时做出明智的选择。
iOS应用程序的初始化
我们知道,iOS应用程序基本上是用Objective C语言编写的,该语言是C语言的一个超集。Xcode对隐藏如何生成应用程序的细节做得非常不错,但在幕后,其实际工作是使用LLVM及其他常见的UNIX工具完成的。因为我们知道项目根本上是一个C语言的应用程序,所以可以预期到应用程序的起点应该是C语言的main函数。事实上,如果查看Supporting Files分组下的内容,会看到main.m文件,其内容如程序清单2-1所示。
程序清单2-1 main.m
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char *argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass
([AppDelegate class]));
}
}
程序清单2-1中的main函数是一个C函数,但你会发现,程序的主体部分明显是Objective C的语法。@autoreleasepool封装了一个到UIApplicationMain的调用。@autoreleasepool用于设置应用程序的内存管理环境,我们并不真正需要担心这一问题。UIApplicationMain函数自动完成很多事项:根据info.plist文件初始化应用程序,设置事件循环,总之是保证程序按正确方式运行。事实上,我从来就没有任何理由要修改此函数,因为iOS提供了一个简洁的位置,以便你开始添加启动代码。开始添加初始化代码的最佳位置是任务application:didFinishLaunchingWithOptions:,可在应用程序委托类的实现文件中找到。在本例中,应用程序委托类名为AppDelegate。程序清单2-2显示了AppDelegate.m中application:didFinishLaunchingWithOptions:任务的实现。
程序清单2-2 application:didFinishLaunchingWithOptions:
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen]
bounds]] autorelease];
// Override point for customization after application launch.
if ([[UIDevice currentDevice] userInterfaceIdiom] ==
UIUserInterfaceIdiomPhone) {
self.viewController = [[[ViewController_iPhone alloc]
initWithNibName:@"ViewController_iPhone" bundle:nil] autorelease];
} else {
self.viewController = [[[ViewController_iPad alloc]
initWithNibName:@"ViewController_iPad" bundle:nil] autorelease];
}
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
应用程序完全初始化后,调用application:didFinishLaunchingWithOptions:任务并运行其中代码,如程序清单2-2所示。这个任务除了具有一个长度令人难以置信的名称外,还需要一个UIApplication的实例和NSDictionary作为实参。其中UIApplication是一个对象,表示正在运行的应用程序的状态。收到此消息的AppDelegate实例是该UIApplication对象的委托。这意味着可以通过实现AppDelegate中的任务来修改应用程序的行为。协议UIApplicationDelegate由AppDelegate实现,其中定义了能够由应用程序调用的任务。
下面介绍application:didFinishLaunchingWithOptions:的实现,首先新建了一个与屏幕尺寸大小相等的UIWindow。该UIWindow被实例化后,我们需要创建一个UIViewController以管理应用程序的UI。一般一个新建的Xcode项目,正如我们刚刚创建的,仅使用单个ViewController类管理UI。我们将为ViewController创建设备专有的子类,从而能够有一个位置放置设备专用的代码。稍后就会看到创建这些子类的过程。为确保我们实例化的ViewController子类正确无误,我们在程序清单2-2中将对应代码加粗。
创建ViewController后,我们将其设置为window的rootViewController,并调用makeKeyAndVisible。window对象是一个UIWindow实例,是应用程序根图形组件。makeKeyAndVisible任务实质上是显示窗口。我们向应用程序添加的任意自定义组件都将作为该window对象的子视图。
如果你的应用程序需要在UI加载之前完成配置,可以将此部分初始化代码放在makeKeyAndVisible调用之前。这有可能包括读取应用程序专有的配置文件、初始化数据库、设置位置服务或者其他任何事情。
接下来首先大致了解一下iOS应用程序是如何组织UI的,然后再学习Interface Builder的使用细节。