<script type="text/javascript"> </script> <script type="text/javascript"> </script>
上一篇我们使用iPhone自带的view-based模板创建了第一个程序HelloWorld。但是在实际工作中,我们最常使用的还是window-based模板,任何一个iPhone程序都可以基于这个模板构建,因为它是最通用的模板。废话不多说,我们开始吧。
这次我们使用window-based模板来创建上一篇中的HelloWorld。
<script type="text/javascript"> </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>
启动xCode,File->New Project->选择window-based模板,给工程取名为HelloWorld。首先来看一看模板都提供了哪些默认的文件。
上图分别是本工程和上一个工程的workspace的截图。可以看到,如果使用window-based模板,在Classes文件夹中少了HelloWorldViewController,在Resources文件夹中少了HelloWorldViewController.xib。这是因为view-based模板给我们提供了所需的view,而window-based模板则把这个任务留给了开发者。
我们再来看一看本工程的HelloWorldAppDelegate.h和.m文件,跟上一篇中的HelloWorldAppDelegate相比,少了
1)HelloWorldViewController* viewController 的声明,
2)和添加view的语句:[window addSubview:viewController.view];
这也是我们需要做的工作。
下面我们来添加一个新的view。
选中Classes文件夹,右键,选择Add->New File->选择iPhone OS下的Cocoa Touch Classes,然后在右边的菜单中选择UIViewController subclass,取名为HelloWorldViewController。(注意:记得选上“Also create "HelloWorldViewController.h"”)这样,我们就添加了控制这个新view的类-HelloWorldViewController。
我们还需要创建一个.xib文件,通过这个xib文件,可以编辑view的UI。选中Resources文件夹,右键,选择Add->New File->选择iPhone OS下的User Interfaces,然后在右边的菜单中选择View XIB,然后取名为HelloWorldViewController。
这样,我们就完成了新view的添加。可以这么理解:.xib文件是这个view的表现层(用户所看到的),而.h和.m文件则是这个view的控制(负责处理用户交互的)。如果我们还记得上一篇提到过的MVC结构,那么.xib就是V,而.h和.m就对应这C。
<script type="text/javascript"> </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>
下面我们来添加代码和控件。
首先,在HelloWorldAppDelegate.h中:
#import <UIKit/UIKit.h>
@class HelloWorldViewController;
@interface HelloWorldAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
HelloWorldViewController *viewController;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) HelloWorldViewController *viewController;
@end
这里在HelloWorldAppDelegate中添加了一个新的成员,就是我们刚添加的view的controller。注意,我们还添加了一句声明:@property (nonatomic, retain) HelloWorldViewController *viewController;
Objective-C中的关键词@property允许我们设置变量的属性。它的具体含义是什么呢?下面来详细解释一下:
在C++ 中,我们通过.运算符来访问成员变量,如aClass.memberVar = 1; 但是在Objective-C中,我们必须实现setter和getter函数才能访问和修改成员变量(如void setMemberVar(int i)和int getMemberVar() )。为了简化编码,Objective-C提供了关键词@property,它告诉编译器为我们生成getter和setter函数。在@property后面,紧跟着一些属性,编译器根据这些属性,为getter和setter生成不同的代码。
1)nonatomic: 在默认情况下,编译器生成getter和setter函数的时候,会添加一些其他代码(主要是考虑到多线程的程序)。这里,我们不需要这些额外的代码,关键词nonatomic就是告诉编译器不要添加这些代码。
2)retain: 在默认情况下,编译器以assign的方式生成setter。而retain则告诉编译器,在生成setter函数的时候,需要调用setter参数的retain方法。如:
*ASSIGN 方式* *RETAIN 方式*
- (void) setString: (NSString*) str { - (void) setString: (NSString*) str {
theString = str; [str retain];
... ... [theString release];
theString = str; ... ...
} }
在HelloWorldAppDelegate.m中,添加:
@synthesize window;
@synthesize viewController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
HelloWorldViewController *ctrl =
[[HelloWorldViewController alloc] initWithNibName:@"HelloWorldViewController"
bundle:[NSBundle mainBundle]];
self.viewController = ctrl;
[ctrl release];
[window addSubview:[self.viewController view]];
// Override point for customization after application launch
[window makeKeyAndVisible];
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
1)@synthesize是真正的生成setter和getter函数的命令。在头文件中出现的@property只是设置属性的命令。
2)程序启动后,会自动装载MainWindow.xib,但是它并不知道要装载HelloWorldViewController.xib。这是我们添加的资源文件,所以在程序装载完MainWindow.xib之后,需要添加代码,让程序来装载HelloWorldViewController.xib。UIViewController中有一个成员变量view,这里HelloWorldViewController继承了UIViewController,自然也有这个成员变量。成员变量view对应于用户看到的UI(这里对应的UI是什么?见下文)。所以,需要将HelloWorldViewController的view添加到window中。
[window addSubview:[self.viewController view]];
3)由于viewController的属性是retain,所以在dealloc中,需要调用release释放资源。
下面我们来编辑这个新view所对应的UI。双击HelloWorldViewController.xib,启动Interface Builder。从控件库中添加UILabel和UIButton。调整控件的大小和位置。保存。
选择File's Owner,然后组合键cmd+4,在Class Identity中输入HelloWorldViewController。这是告诉Interface Builder将这个资源与HelloWorldViewController这个类联系起来。这样,我们就能够通过Interface Builder将这个资源中的控件与HelloWorldViewController类中的代码联系起来。
在HelloWorldViewController.h中,添加:
@interface HelloWorldViewController : UIViewController {
IBOutlet UILabel * m_label;
}
@property (nonatomic, retain) IBOutlet UILabel * m_label;
- (IBAction) onClick;
@end
由于我们需要修改UILabel中的文字,所以需要在代码声明这个UILabel,然后利用Interface Builder将这个变量和控件联系起来。同时,我们还声明了函数onClick,用来处理按键事件。同样,我们也要用Interface Builder将这个函数和控件事件联系起来。
在HelloWorldViewController.m中,添加:
@implementation HelloWorldViewController
@synthesize m_label;
... ...
- (IBAction) onClick {
m_label.text = @"Hello World!";
}
- (void)dealloc {
[m_label release];
[super dealloc];
}
<script type="text/javascript"> </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>
然后就是用Interface Builder将它们和控件联系起来:
选中File's Owner,按住ctrl,点击鼠标左键并拖拽鼠标至UILabel上方,释放左键,选择m_label。这样就将变量和控件联系起来了。
选中控件UIButton,组合键cmd+2,选择Touch Up Inside,将鼠标移至Touch Up Inside右边的圆圈上(变成×),然后拖拽鼠标至File's Owner,释放左键,选择onClick。这样就完成了鼠标事件和函数的连接。
最后一步:上面我们提到过,UIViewController有一个成员变量view,这个view有对应的UI。很显然这里所谓的对应的UI,就是刚才我们使用Interface Builder编辑过的控件View(我们之前用Interface Builder添加了UIButton和UILabel到控件View中;在HelloWorldViewController.xib中,我们看到View旁边是一个小箭头,点击展开,下面有UILabel和UIButton),现在我们需要将UIViewController这个类中的成员变量view和控件View联系起来。这样,在运行代码:[window addSubview:[self.viewController view]]; 的时候,程序才知道需要装载哪个view。
选中File's Owner,组合键cmd+2,在Outlets下面,可以看到view现在没有和任何控件联系起来。将鼠标移至view右边的圆圈上(变成×),然后按住左键并拖拽鼠标至HelloWorldViewController.xib中的View上方,然后释放鼠标。这样,我们就完成了连接。
(上文中出现了两个不同的view,一个是UIViewController的成员变量view,另一个是控件View)
编译,运行!我们就得到了和上一篇一样的Hello World!