本章主要讲解了UIViewController及其控制对象的视图之间的关系,视图的生命周期,和UITabBarController的基本用法,NSDate获取当前时间转换为字符串的方法。
demo讲解:
1.创建HypnoTime工程(本人习惯创建“空工程”),在appdelegate.m中创建一个UITabBarController.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
//创建UITabBarController对象
UITabBarController *tabBarController = [[UITabBarController alloc] init];
//创建两个子视图控制对象实例
UIViewController *vc1 = [[HypnosisViewController alloc] init];
UIViewController *vc2 = [[CurrentTimeViewControoler alloc] init];
//创建包含以上两个视图控制对象的数组对象
NSArray *viewControllers = [NSArray arrayWithObjects:vc1, vc2, nil];
//将新的视图对象加入UITabBarController对象
[tabBarController setViewControllers:viewControllers];
//将tabBarController设为window的rootViewController
[self.window setRootViewController:tabBarController];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
其中的HypnosisViewController和CurrentTimeViewController会在下面讲到。UITabBarController的基本使用流程就是创建若干UIViewController实例,然后将其加到一组NSArray中。本例将UITabBarController设为程序的根视图控制对象。
2。创建HypnisisViewController和CurrentTimeViewController两个类。
HypnosisViewController.m
显示第六章中的同心圆和字符视图
- (id)init
{
//调用父类的指定方法
self = [super initWithNibName:nil bundle:nil];
if (self) {
//得到标签项
UITabBarItem *tbi = [self tabBarItem];
//为标签项设置标题
[tbi setTitle:@"Hypnosis"];
//通过文件创建UIImage对象
UIImage *i = [UIImage imageNamed:@"Hypno.png"];
//将该UIImage对象加入标签条项目
[tbi setImage:i];
}
return self;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
//忽略参数——使用控制对象的内部默认实现来决定nib文件名
return [self init];
}
//创建视图时,这个方法会被调用
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"Loaded the view for HypnosisViewController");
//设置视图的背景颜色以便查看
//[self.view setBackgroundColor:[UIColor orangeColor]];
}
- (void)loadView
{
HypnosisView *hv = [[HypnosisView alloc] initWithFrame:CGRectZero];
[hv setBackgroundColor:[UIColor whiteColor]];
[self setView:hv];
}
CurrentTimeViewController.m
用于显示当前时间
#define kTime @"What time is it?"
@implementation CurrentTimeViewControoler
- (id)init
{
//调用父类的指定方法
self = [super initWithNibName:nil bundle:nil];
if (self) {
//得到标签项
UITabBarItem *tbi = [self tabBarItem];
//为标签项设置标题
[tbi setTitle:@"Time"];
UIImage *i = [UIImage imageNamed:@"Time.png"];
[tbi setImage:i];
}
return self;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
//忽略参数——使用控制对象的内部默认实现来决定nib文件名
return [self init];
}
//创建视图时,这个方法会被调用
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"Loaded the view for CurrentTimeViewController");
//设置视图的背景颜色以便查看
//[self.view setBackgroundColor:[UIColor greenColor]];
timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(60, 100, 200, 44)];
timeLabel.textAlignment = NSTextAlignmentCenter;
timeLabel.font = [UIFont boldSystemFontOfSize:18];
timeBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
timeBtn.frame = CGRectMake(40, 200, 240, 44);
timeBtn.titleLabel.font = [UIFont boldSystemFontOfSize:18];
[timeBtn setTitle:kTime forState:UIControlStateNormal];
[timeBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[timeBtn addTarget:self action:@selector(showCurrentTime:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:timeBtn];
[self.view addSubview:timeLabel];
}
//刷新视图时更新时间
- (void)viewWillAppear:(BOOL)animated
{
NSLog(@"CurrentTimeViewController will appear");
[super viewWillAppear:animated];
[self showCurrentTime:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
NSLog(@"CurrentTimeViewController will disappear");
[super viewWillDisappear:animated];
}
- (void)showCurrentTime:(id)sender
{
NSDate *now = [NSDate date];
/*
static意为“只创建一次”
在应用首次载入内存时,会创建formatter变量
第一次运行本方法时,formatter的值是nil
所以会执行if语句块,创建NSDateFormatter对象,并将指针赋给formatter变量
此后再执行这个方法,会重用之前创建的NSDateFormatter对象
*/
static NSDateFormatter *formatter = nil;
if (!formatter) {
formatter = [[NSDateFormatter alloc] init];
[formatter setTimeStyle:NSDateFormatterMediumStyle];
}
[timeLabel setText:[formatter stringFromDate:now]];
}
@end
覆盖UIViewController的init方法,在控制对象创建是设置其tabBarItem,注意tabBarItem的图像像素标准为30x30。
HypnosisView为第六章中的HypnosisView。
3.视图控制对象的生命周期与内存过低警告
(此处为个人的理解)UIVIewController的实例会在内存中一直存在,但其控制的视图(即self.view)会在内存过低时被回收掉。视图会在控制对象(即controller)第一次接收到view消息([self view]或self.view)时创建。view方法如下
- (UIView *)view
{
if ([self isViewLoaded] == NO) {
[self loadView];
[self viewDidLoad];
}
return view;
}
可以看出,视图其实是通过loadView和viewDidLoad方法完成的。由此可见,我们不应该在controller的init方法中访问view(即发送view消息),否则内存过低时,该view无法被释放(上面讲的,controller一直存在在内存中)。
视图的生命周期(或者说各个方法的前后执行顺序为)
视图未存在时:
controller第一次接收到view消息 ----> view ----> loadView ----> viewDidLoad ----> viewWillAppear ----> viewDidAppear ----> viewWillDisappear ----> viewDidDisappear;
视图已存在时:
viewWillAppear ----> viewDidAppear ----> viewWillDisappear ----> viewDidDisappear;
当收到内存警告时,self.view = nil ----> viewDidUnload。