首页 » iOS编程(第4版) » iOS编程(第4版)全文在线阅读

《iOS编程(第4版)》24.7 保存视图状态

关灯直达底部

现在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现在可以很好地保存和恢复整个应用的状态,提供了流畅的用户体验。