1.3 不使用Interface Builder的Hello World程序

上一节我们使用Interface Builder工具创建完成了Hello World应用程序,前一节我们已经介绍过了,我们创建这个Hello World应用程序的主要目的是了解UIkit框架中控件类(如UITableView等)的使用方法,其实Interface Builder中制作界面时使用的就是UIkit框架中的控件类,只不过是使用一种所见即所得的方式来完成界面的设计,另外Interface Builder中还有其他外面看不到的处理。

不可否认Interface Builder是一款设计得非常完美的开发工具,使用起来也非常方便。但是我们如果想更深入理解UIKit框架及其中的控件类的话,最好还是撇开Interface Builder,采取直接编写代码的方式来进行开发,我们可以从中了解到那些由Interface Builder完成的,被隐藏起来的工作,最后真正理解UIKit框架的工作原理,有助于完成更复杂iPhone应用程序的设计。

而本节将讲解如何将上面的Hello World工程改造成不使用Interface Builder的工程,其实就是去掉了工程中的xib文件,而直接编写控件代码。今后就可以利用这个工程测试各种UIkit框架中的控件类。

1.3.1 编辑HelloWorldAppDelegate.m

为了实现去掉HelloWorld工程中的MainWindow.xib文件,我们首先要重新编辑HelloWorldAppDelegate.m文件,将MainWindow.xib中完成的工作转移到HelloWorldApp Delegate.m中完成。

在代码编辑窗口双击HelloWorldAppDelegate.m文件,编辑HelloWorldApp Delegate.m application:didFinishLaunchingWithOptions方法,其他的只有框架的方法可以删除掉,如果保留也没有什么问题。方法application:didFinishLaunchingWithOptions中追加的代码如下。

-(void)applicationDidFinishLaunching:(UIApplication *)application {
  // 取得与应用程序窗口相同大小的矩形
  CGRect rect = [window frame];
  // 创建UILabel的实例,并初始化
  // 生成与应用窗口大小相同的UILabel
  UILabel* label = [[UILabel alloc] initWithFrame:rect];
  // 在UILabel中显示信息为“Hello,world!”
  label.text = @"Hello,world!";
  // 将创建完成的UILabel追加到Window中
  [window addSubview:label];
  // 最后请不要忘记了执行release
  [label release];
    // Override point for customization after application launch
    [window makeKeyAndVisible];
}

代码追加在application:didFinishLaunchingWithOptions方法中事先已有调用makeKeyAndVisible方法的代码前。

上述新追加的代码大致依次完成如下的工作。

  • UILabel对象的创建以及初始化。
  • 向UILabel对象设置“Hello World!”信息。
  • 将UILabel对象加入到Window(窗口)中。

UILabel是创建标签的类。UILabel创建完成后,使用initWithFrame:方法进行初始化。在initWithFrame:方法的参数中需要指定具体的位置以及大小,这里为了方便,将其指定为与应用程序的窗口(Window)相同的位置及大小。Window的frame属性中保存了窗口的位置及大小,将这个frame属性直接传入到initWithFrame:方法的参数中是最简便的。

UILabel的初始化完成后,接着就是将UILabel对象的text属性设置为“Hello World!”,最后使用addSubview:方法将UILabel对象追加到Window中。我们从第1.1节看到Window对象的类UIWindow是UIView的子类,而UILabel也是UIView的子类。addSubview:方法正是在UIView类中定义的方法,负责将UIView对象追加到其他UIView对象中。

最后,不要忘记了对追加完成的UILabel对象执行release,这是实现参照统计式内存管理的需要。

1.3.2 删除MainWindow.xib文件

我们只有将MainWindow.xib文件删除了之后,才可以说告别了Interface Builder。

选择“Groups & Files”最上层的HelloWorld,Xcode的中央窗口会显示工程包含的所有文件及框架(见图1-12)。选中MainWindow.xib文件,单击鼠标右键,选择“delete”命令后,在对话框中单击“Also Move to Trash”按钮(见图1-13),即可将MainWindow.xib文件物理删除。

光进行上述的物理删除动作,还不能说完全删除了MainWindow.xib文件的残余,我们还必须编辑info.plist文件。双击图1-12窗口中的HelloWorld-info.plist文件,我们可以发现在info.plist文件的编辑窗口(见图1-14)的最后有key名为“Main nib file base name”的项目,单击鼠标右键,在弹出的快捷菜单中选择“cut”命令,即可将此项删除。这样与MainWindow.xib文件相关的所有信息都被删除干净了。

图1-12 删除MainWindow.xib文件

图1-13 单击“Also Move to Trash”按钮

图1-14 编辑info.plist文件

1.3.3 编辑main.m文件

删除了MainWindow.xib文件,算是彻底删除创建窗口的处理了。我们要复活创建窗口的处理,首先要编辑main.m文件。双击图1-12所示窗口中的main.m文件,打开编辑窗口。将其中调用UIApplicationMain函数的行修改成如下代码所示。

// 原代码
// int retVal = UIApplicationMain(argc,argv,nil,nil);
// 只修改第4个参数
int retVal = UIApplicationMain(argc,argv,nil,@"HelloWorld AppDelegate");

这样的修改,是将原来自动设置的应用程序委托(本例为HelloWorldAppDelegate,所谓应用程序委托,是当应用程序状态变化时接收通知的对象,为继承了UIApplicationDelegate协议类的实例),在此明确指定它罢了。UIApplicationMain函数的第4个参数正是用于指定应用程序委托的参数。如果此参数为nil,会根据info.plist文件中设置的nib或者xib文件,自动决定应用程序委托。因为前面已经删除了xib文件,在此必须指定字符串“HelloWorldAppDelegate”代表的类名,来决定应用程序委托。

1.3.4 再次编辑HelloWorldAppDelegate.m文件

编辑完了main.m,还不能够正常编译整个HelloWorld工程,在HelloWorldAppDelegate.m文件中,有编程经验的读者可能注意到,Window实例变量还没有被初始化。因此还必须再编辑一下HelloWorldAppDelegate.m文件完成Window实例变量的初始化动作。

需要在application:didFinishLaunchingWithOptions:方法的最上部追加如下初始化Window实例变量的代码。

// 自己创建Window对象
CGRect bounds = [[UIScreen mainScreen] bounds];
window = [[UIWindow alloc] initWithFrame:bounds];

上述代码正是将以前由MainWindow.xib自动创建的窗口(UIWindow)实例,在此自己手动创建的代码。

UIWindow实例的创建不是一件很难的事情,先调用alloc方法生成UIWindow的实例,然后调用initWithFrame方法对其进行初始化。此处,需要取出UIScreen类的bounds属性作为画面的大小,并以参数的形式传入。

最后还有一个工作需要完成,那就是删除HelloWorldAppDelegate.m文件中的IBOutlet关键字。实际上如果不删除,应用程序也不会有任何问题,IBOutlet关键字是Interface Builder识别插座变量的标志,留在程序中也没有任何意义。

到此为止,我们已清除了所有与Interface Builder相关的内容,下面可以测试一下应用程序的执行结果,单击Xcode窗口上部的“Build and Debug”按钮,编译建立完成后,显示如图1-15所示的画面。如果想让字符串“Hello World!”居中显示,可以修改相关属性,有兴趣的读者可自行完成。

图1-15 HelloWorld结果画面