视图控制器(viewcontroller)是UIViewController类或其子类的对象。每个视图控制器都负责管理一个视图结构,包括创建视图层次结构中的视图并处理相关用户事件,以及将整个视图层次结构添加到应用窗口。
创建一个UITabBarController在两个视图层次结构之间(Hypnotize和Reminder)切换,Riminder包含两个子视图,一个UIDatePicker对象和一个UIbutton对象。
视图控制器不会在其被创建出来的那一刻马上创建并载入相应的视图。只有当应用需要将某个视图控制器的视图显示到屏幕上时,相应的控制器才会创建其视图。这种延迟加载(lazy loading)视图的做法能提高内存使用效率。
视图控制器可以通过两种方式创建视图层次结构:
代码方式:覆盖UIViewcontroller中的loadView方法
NIB文件方式:使用interface Builder创建一个NIB文件,然后加入所需的视图层次结构,最后视图控制器会在运行时加载由该NIB文件编译而成的XIB文件(应用在运行时,会按需载入XIB文件并激活文件中的视图)。
1. 创建Hypnotize视图
1.1 代码方式创建视图
BNRHypnosisViewController.m文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| @implementation BNRHypnosisViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) {
self.tabBarItem.title = @"Hypnotize";
UIImage *image = [UIImage imageNamed:@"Hypno.png"];
self.tabBarItem.image = image; }
return self; }
- (void)loadView { CGRect frame = [UIScreen mainScreen].bounds; BNRHypnosisView *backgroundView = [[BNRHypnosisView alloc] initWithFrame:frame];
self.view = backgroundView; }
- (void)viewDidLoad { [super viewDidLoad];
NSLog(@"BNRHypnosisViewController loaded its view"); }
@end
|
1.2 设置根视图控制器
为了将视图控制器的视图层次结构加入应用窗口,UIWindow对象提供了一个方法:setRootViewController:。当程序将某个视图控制器设置为UIWindow对象的rootViewController时,UIWindow对象会将该视图控制器的view作为子视图加入窗口,并且还会自动调整view的大小,将其设置为与窗口的大小相同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @implementation BNRAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
BNRHypnosisViewController *hvc = [[BNRHypnosisViewController alloc] init];
BNRReminderViewController *rvc = [[BNRReminderViewController alloc] init];
UITabBarController *tabBarController = [[UITabBarController alloc] init]; tabBarController.viewControllers = @[hvc, rvc];
self.window.rootViewController = tabBarController;
self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES; }
|
rootViewController的view在应用启动完毕后就显示,因此,UIWindow对象会在设置完rootViewController后立即加载其view。
以下是setRootViewController:的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| -(void)setRootViewController:(UIViewController *)viewController { UIView *rootView = viewController.view; CGRect viewFrame = self.bounds; rootView.frame = viewFrame; [self addSubview:rootView]; _rootViewController = viewController; }
|
2. 创建Reminder视图
因为BNRReminderViewController包含两个子视图UIdatePicker和UIbutton,因此需要添加一个dataPicker属性,指向一个UIDatePicker对象。同时,将BNRViewController设置为UIButton对象的目标,还需编写一个addReminder:方法,并设置为UIButton对象的动作。
BNRReminderViewController对象的view有两个子视图,当某个视图控制器的view拥有子视图时,使用interface Builder创建视图层次会较方便。
2.1 Interface Builder中创建视图
创建一个xib文件,在File菜单选择new-file…,选择User interface,再选中Empty。
2.1.1 创建视图对象
从xcode右下方对象库拖拽UIview,UIbutton,UIdatePicker至画布。
2.1.2 加载nib文件
当视图控制器从NIB文件中创建试图层次结构时,不需要覆盖loadview方法,默认的loadview会自动处理NIB文件包含的视图层次结构。
接下来,用以下方法为reminder加载NIB文件
-(id)initWithNibName:(NSString )nibNameOrNil bundle:(NSBundle )nibBundleOrNil
上述方法两个参数,分别用于指定NIB文件的文件名及其所在的程序包
2.1.3 关联Files‘s Owner
Files’s owner对象是一个占位符对象(placeholder),它是XIB文件特意留下的一个“空洞”。当某个视图控制器将XIB文件加载为NIB文件时,首先会创建XIB文件中所有的视图对象,然后会将自己填入相应的File‘s Owner空洞,并建立之前在Interface Builder中设置的关联。
因此,如果要在运行时关联加载NIB文件的对象,可在XIB文件中关联File’s Owner。首先,需要设置BNRReminderViewController.xib文件中的File‘s Owner是BNRReminderViewController。
接着,在XIB文件中添加所需关联:1,Ctrl+左键点击File‘s owner,在插座变量outlet部分找到view,鼠标连线至右侧视图控制器的View属性;2,同理关联datepicker;3,将UIbutton关联到File’s owner的addReminder方法。
BNRReminderViewController.m完整代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| #import "BNRReminderViewController.h"
@interface BNRReminderViewController ()
@property (nonatomic, weak) IBOutlet UIDatePicker *datePicker;
@end
@implementation BNRReminderViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) { self.tabBarItem.title = @"Reminder"; UIImage *image = [UIImage imageNamed:@"Time.png"];
self.tabBarItem.image = image; }
return self; }
- (void)viewDidLoad { [super viewDidLoad];
NSLog(@"BNRReminderViewController loaded its view"); }
- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated];
self.datePicker.minimumDate = [NSDate dateWithTimeIntervalSinceNow:60]; }
- (IBAction)addReminder:(id)sender { NSDate *date = self.datePicker.date; NSLog(@"Setting a reminder for %@", date);
UILocalNotification *note = [[UILocalNotification alloc] init]; note.alertBody = @"Hypnotize me!"; note.fireDate = date;
[[UIApplication sharedApplication] scheduleLocalNotification:note]; }
|
在BNRAppdelegate.m中,创建一个BNRReminderViewCOntroller对象,再将其设置为应用程序
3. UITabBarController
UITabBarController对象可以保存一组视图控制器,此外UITabBarController还会在底部显示一个标签栏(tab bar),标签栏会有多个标签项(tab item)
3.1 设置标签项
设置tabbaritem的title以及image属性
4. 视图控制器初始化方法
当UIViewController子类和该子类需要加载的NIB文件同名时,即使用在appdelegate调用init初始化,传给vieController两个参数为nil,也能正常调用以下初始化,并正确加载
-(id)initWithNibName:(NSString )nibNameOrNil bundle:(NSBundle )nibBundleOrNil
5. 添加本地通知
1 2 3 4 5 6 7 8 9 10 11
| - (IBAction)addReminder:(id)sender { NSDate *date = self.datePicker.date; NSLog(@"Setting a reminder for %@", date);
UILocalNotification *note = [[UILocalNotification alloc] init]; note.alertBody = @"Hypnotize me!"; note.fireDate = date;
[[UIApplication sharedApplication] scheduleLocalNotification:note]; }
|
6. 加载和显示视图
为了实现延迟加载,在initWithNibName:bundle 中不应访问view或view的任何子视图,凡是和view或view子视图有关的初始化代码,都放在 viewDidLoad中,避免加载时加载不需要在屏幕上显示的视图。
7. 访问视图
alloc【创建对象,分配空间】—>init (initWithNibName)【初始化对象,初始化数据】—> loadView【从nib载入视图 ,通常这一步不需要去干涉。除非你没有使用xib文件创建视图】—> viewDidLoad—> viewWillAppear—>viewDidAppear—> viewWillDisappear—> viewDidDisappear—> dealloc
内存不足时,调用viewDidUnload函数释放views—->当需要使用view时,又回到loadview如此循环