视图是应用的一个重要组成部分,功能的实现与其息息相关,而视图控制器控制着视图,其重要性在整个应用中不言而喻。 2.4.1 视图生命周期与视图控制器关系 以视图的4种状态为基础,我们来系统了解一下视图控制器的生命周期。在视图不同的生命周期中,视图控制器会回调不同的方法,具体如图2-27所示。 图2-27 视图控制器的一些主要方法 在视图控制器已被实例化,视图被加载到内存中时调用viewDidLoad方法,这个时候视图并未出现。在该方法中,通常进行的是对所控制的视图进行初始化处理。 视图可见前后会调用viewWillAppear:方法和viewDidAppear:方法;视图不可见前后会调用viewWillDisappear:方法和viewDidDisappear:方法。 4个方法调用父类相应的方法以实现其功能,编码时该方法的位置可根据实际情况做以调整,参见如下代码: -(void)viewWillAppear:(BOOL)animated { [super viewWillAppear:YES]; …… } viewDidLoad方法在应用运行的时候只调用一次,而这上述4个方法可以被反复调用多次,它们的使用很广泛但同时也具有很强的技巧性。例如,有的应用会使用重力加速计,重力加速计会不断轮询设备以实时获得设备在z轴、x轴和y轴方向的重力加速度。不断的轮询必然会耗费大量电能进而影响电池使用寿命,我们通过利用这4个方法适时地打开或者关闭重力加速计来达到节约电能的目的。怎么使用这4个方法才能做到“适时”是一个值得思考的问题。 在低内存情况下,iOS会调用didReceiveMemoryWarning:和viewDidUnload:方法。在iOS 6之后,就不再使用viewDidUnload:,而仅支持didReceiveMemoryWarning:。didReceiveMemoryWarning:方法的主要职能是释放内存,包括视图控制器中的一些成员变量和视图的释放。现举例如下: - (void)didReceiveMemoryWarning { self.button = nil; self.myStringD = nil; [myStringC release]; [super didReceiveMemoryWarning]; } 除了上述5个方法视图控制器外,还有很多其他方法,随着学习的深入,我们会逐一向大家介绍。 2.4.2 iOS 6 UI状态保持和恢复 iOS设计规范中要求,当应用退出的时候(包括被终止运行的时候),需要保持界面中UI元素的状态,当再次进来的时候看到的状态与退出时是一样的。在iOS 6之后,苹果提供以下API使得UI状态保持和恢复变得很容易。 在iOS 6中,我们可以在以下3种地方实现状态保持和恢复: 应用程序委托对象 视图控制器 自定义视图 为了演示这个功能,我们把基于故事板的HelloWorld工程改造一下。在界面中添加一个文本框,操作与在2.1节中添加Label控件类似,如图2-28所示。关于文本框的技术细节,我们会在后面的章节中介绍。 图2-28 视图添加文本框 用户在文本框中输入一些内容,应用程序退出并且终止,当用户再次进来的时候,文本框中还会保持原来输入的内容。然后在Interface Builder的Scene中选中View Controller,打开右边的标识检查器 ,如图2-29所示,设置Restoration ID(恢复标识)为viewController。 图2-29 设置控制器的恢复标识 恢复标识是iOS 6为了实现UI状态保持和恢复添加的设置项目。我们还需要在应用程序委托对象AppDelegate代码部分做一些修改,添加的代码如下: -(BOOL) application:(UIApplication *)application shouldSaveApplicationState: (NSCoder *)coder { return YES; } -(BOOL) application:(UIApplication *)application shouldRestoreApplicationState: (NSCoder *)coder { return YES; } - (void)application:(UIApplication *)application willEncodeRestorableStateWithCoder: (NSCoder *)coder { [coder encodeFloat:2.0 forKey:@"Version"]; } - (void)application:(UIApplication *)application didDecodeRestorableStateWithCoder: (NSCoder *)coder { float lastVer = [coder decodeFloatForKey:@"Version"]; NSLog(@"lastVer = %f",lastVer); } 其中application:shouldSaveApplicationState:方法在应用退出时调用,负责控制是否允许保存状态,返回YES情况是可以保存,NO是不保存。 application:shouldRestoreApplicationState:方法在应用启动时调用,负责控制是否恢复上次退出时的状态,返回YES表示可以恢复,返回NO表示不可以恢复。 application:willEncodeRestorableStateWithCoder:方法在保存时调用,在这个方法中实现UI状态或数据的保存,其中[coder encodeFloat:2.0 forKey:@"Version"]语句是保存简单数据。 application:didDecodeRestorableStateWithCoder:方法在恢复时调用,在这个方法中实现UI状态或数据的恢复,其中[coder decodeFloatForKey:@"Version"]语句用于恢复上次保存的数据。 想要实现具体界面中控件的保持和恢复,还需要在它的视图控制器中添加一些代码。我们在ViewController.m中添加的代码如下: -(void)encodeRestorableStateWithCoder:(NSCoder *)coder { [super encodeRestorableStateWithCoder:coder]; [coder encodeObject:self.txtField.text forKey:kSaveKey]; } -(void)decodeRestorableStateWithCoder:(NSCoder *)coder { [super decodeRestorableStateWithCoder:coder]; self.txtField.text = [coder decodeObjectForKey:kSaveKey]; } 在iOS 6之后,视图控制器都添加了两个方法——encodeRestorableStateWithCoder:和decodeRestorable- StateWithCoder:,用来实现该控制器中的控件或数据的保存和恢复。其中encodeRestorableStateWithCoder:方法在保存时候调用,[coder encodeObject:self. txtField.textforKey:kSaveKey]语句是按照指定的键保存文本框的内容,decodeRestorableStateWithCoder:方法在恢复时调用,[coder decodeObjectForKey:kSaveKey]在恢复文本框内容时调用,保存和恢复事实上就是向一个归档文件中编码和解码的过程。 为了测试是否能够保持和恢复,我们可以将工程属性文件HelloWorld-Info.plist中的相关属性Application does not run in background设置为YES,使应用退出时终止程序的运行。