现在BNRItemsViewController中还存在以下问题:
•UITableView没有记录用户最后选中的BNRItem和滚动位置。
•BNRItemsViewController没有记录用户最后是位于正常模式还是编辑模式。每次重新启动应用后,BNRItemsViewController都会恢复到正常模式。
类似于UIViewController,同样可以为UIView及其子类设置恢复标识,并保存需要的状态信息。iOS SDK提供的部分UIView子类可以自动保存某些状态信息,例如UICollectionView、UIImageView、UIScrollView、UITableView、UITextField、UITextView和UIWebView。
Xcode文档中详细介绍了这些类会保存哪些状态信息。为了记录用户最后的滚动位置,可以使用UITableView自动保存的contentOffset属性,恢复UITableView的滚动位置。
先打开BNRItemsViewController.m,为UITableView对象设置恢复标识,代码如下:
- (void)viewDidLoad
{
[super viewDidLoad];
// 创建UINib对象,该对象代表包含了BNRItemCell的NIB文件
UINib *nib = [UINib nibWithNibName:@“BNRItemCell” bundle:nil];
// 通过UINib对象,注册相应的NIB文件
[self.tableView registerNib:nib
forCellReuseIdentifier:@“BNRItemCell”];
self.tableView.restorationIdentifier =
@“BNRItemsViewControllerTableView”;
}
构建并运行应用,多添加一些BNRItem对象,然后向下滚动UITableView对象。触发状态恢复,再重新启动应用。可以看见,UITableView对象可以正确恢复到之前滚动的位置。
接下来解决第二个问题,保存BNRItemsViewController的编辑状态。打开BNRItemsViewController.m,实现编码和解码方法,代码如下:
- (void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
[coder encodeBool:self.isEditing forKey:@“TableViewIsEditing”];
[super encodeRestorableStateWithCoder:coder];
}
- (void)decodeRestorableStateWithCoder:(NSCoder *)coder
{
self.editing = [coder decodeBoolForKey:@“TableViewIsEditing”];
[super decodeRestorableStateWithCoder:coder];
}
下面介绍如何记录用户最后选中的BNRItem。UITableView会自动记录最后选中的UITableViewCell,但无法正确找到UITableViewCell所对应的BNRItem。也就是说,UITableView只会恢复视图对象(每一行的UITableViewCell),但无法自动为其关联正确的模型对象(每一行UITableViewCell所对应的BNRItem)。
在BNRItemsViewController.m的类扩展中,使BNRItemsViewController遵守UIDataSourceModelAssociation协议:
@interface BNRItemsViewController ()
<UIPopoverControllerDelegate,UIDataSourceModelAssociation>
@property (nonatomic, strong) UIPopoverController *imagePopover;
@end
UIDataSourceModelAssociation协议可以帮助系统在恢复视图对象时为其关联正确的模型对象。当系统保存视图状态时,会同时根据该视图对应模型的所在位置(NSIndexPath)保存一个唯一标识;之后,当恢复视图状态时,也会同时恢复该唯一标识,并找到模型之前的位置。这样,就可以将模型关联到对应位置的UITableViewCell。
在BNRItemsViewController.m中,实现UIDataSourceModelAssociation协议的modelIdentifierForElementAtIndexPath:方法,为选中的BNRItem对象设置唯一标识符(unique identifier),以便系统在恢复应用状态时可以正确找到相应的BNRItem对象。可以使用BNRItem对象的itemKey属性作为唯一标识符,代码如下:
- (NSString *)modelIdentifierForElementAtIndexPath:(NSIndexPath *)path
inView:(UIView *)view
{
NSString *identifier = nil;
if (path && view) {
// 为NSIndexPath参数所对应的BNRItem对象设置唯一标识符
BNRItem *item = [[BNRItemStore sharedStore] allItems][path.row];
identifier = item.itemKey;
}
return identifier;
}
接下来实现该协议的另一个对应方法:indexPathForElementWithModelIdentifier:,根据BNRItem对象的唯一标识符返回其所在的NSIndexPath,代码如下:
- (NSIndexPath *)indexPathForElementWithModelIdentifier:
(NSString *)identifier inView:(UIView *)view
{
NSIndexPath *indexPath = nil;
if (identifier && view) {
NSArray *items = [[BNRItemStore sharedStore] allItems];
for (BNRItem *item in items) {
if ([identifier isEqualToString:item.itemKey]) {
int row = [items indexOfObjectIdenticalTo:item];
indexPath = [NSIndexPath indexPathForRow:row inSection:0];
break;
}
}
}
return indexPath;
}
构建并运行应用,触发状态恢复。Homepwner现在可以很好地保存和恢复整个应用的状态,提供了流畅的用户体验。