UI状态保存和恢复(三)

UI状态保存和恢复(三)

前面两篇我们介绍了UI状态保存和恢复的流程,UIStateRestoration协议类的方法,适用场景,调试策略,UIApplication,UIViewController,UIView关于UIStateRestoration协议所提供的接口方法以及如何实现UI状态保存和恢复。本篇我们将介绍UIStateRestoration协议类中的UIDataSourceModelAssociation协议。

关于UIDataSourceModelAssociation协议

引用官网的解释

Your data source objects can adopt this protocol to assist a corresponding table or collection view during the state restoration process. Those classes use the methods of this protocol to ensure that the same data objects (and not just the same row indexes) are scrolled into view and selected.
//你的数据源对象可以实现这个协议,在状态恢复的过程中去支持相关的table or collection view;这些实现了该协议的类,使用这个协议的方法去保证相同的数据对象,(而不仅仅是相同的行的索引)被滚动到视图并且被选中。
Before you can implement this protocol, your app must be able to identify data objects consistently between app launches. This requires being able to take some identifying marker of the object and convert that marker into a string that can then be saved with the rest of the app state. For example, a Core Data app could convert a managed object’s ID into a URI that it could then convert into a string.
//在你实现这个协议之前,你的App必须能够在App启动之间,一直(总是可以)辨别出数据源对象。这就要求对象能够有一些辨认标识,并且可以把标识转换为当App状态不活跃时能够被存储的字符串;
Currently, only the UITableView and UICollectionView classes support this protocol. You would implement this protocol in any objects you use as the data source for those classes. If you do not adopt the protocol in your data source, the views do not attempt to restore the selected and visible rows.
//目前,只有 UITableView 和 UICollectionView 类 支持这个协议。你将可以实现这个协议在任何你用来作为UITableView 和 UICollectionView数据源的对象中,如果在你的数据源对象中不实现这个协议,那么视图将不会试着去恢复选中的和可见rows;

我们可以获取到的主要信息有:

  • 只有 UITableViewUICollectionView类支持这个协议。
  • 我们的数据源中的每个数据对象(model)必须具备唯一辨认标识。
  • 使用这个协议的方法去保证相同的数据对象,(而不仅仅是相同的行的索引)被滚动到视图并且被选中。举个场景的例子:TableView的数据源对象在上次保存时,所保存的行的索引,可能会因为在当前运行周期内数据源中数据的变动发生变化。从而导致当前选中的行所对应的数据并非上次保存时的数据。
  • 若需要使用UIDataSourceModelAssociation,则:实现了UITableView 和 UICollectionView数据源协议的对象,负责实现这个协议的方法,否则不会生效。实际操作发现确实如此。

除了官网解释,在实际操作中发现还需要设置UITableView 或UICollectionView的restorationIdentifier,否则UIDataSourceModelAssociation协议方法不会被调用。关于UITableView的restorationIdentifier查阅官方文档如下:

To save and restore the table’s data, assign a nonempty value to the table view’s restorationIdentifier property. When its parent view controller is saved, the table view automatically saves the index paths for the currently selected and visible rows. If the table’s data source object adopts the UIDataSourceModelAssociation protocol, the table stores the unique IDs that you provide for those items instead of their index paths.

UITableView设置了restorationIdentifier,进行UI的保存时,tableView会自动存储当前选中和可见行的索引。补充:还会存储滚动偏移,并可以恢复。

UIDataSourceModelAssociation使用
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    InfoModel *model = [self.dataSource objectAtIndex:indexPath.row];
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass(UITableViewCell.class) forIndexPath:indexPath];
    cell.textLabel.text = model.title;
    cell.restorationIdentifier = model.identifier;
    
    return cell;
}
- (NSString *)modelIdentifierForElementAtIndexPath:(NSIndexPath *)idx inView:(UIView *)view {
    //根据index 返回identifier
    NSString *identifier = nil;
    InfoModel *model = [self.dataSource objectAtIndex:idx.row];
    
    /*
     注释①
     if (idx && view) {
       identifier = model.identifier;
    }
    */
    if (idx.row == _currentPath.row && view) {
        identifier = model.identifier;
    }
    //若是不定义_currentPath追踪当前选中的cell.会多保存一个cell,目前尚未有答案。
    return identifier;
}
//此方法 恢复时调用
- (NSIndexPath *)indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view {
    //根据identifier 返回index;
    NSIndexPath *indexPath = nil;
    if (identifier && view) {
        __block NSInteger row = 0;
        [self.dataSource enumerateObjectsUsingBlock:^(InfoModel *obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([obj.identifier isEqualToString:identifier]) {
                row = idx;
                *stop = YES;
            }
        }];
        indexPath = [NSIndexPath indexPathForRow:row inSection:0];
        _currentPath = indexPath;
        NSLog(@"当前选中的数据源对象标识是:%@,对象抬头是:%@",[self.dataSource[indexPath.row] identifier],[self.dataSource[indexPath.row] title]);
    }

    return indexPath;
}

上述代码方法-(NSString *)modelIdentifierForElementAtIndexPath:(NSIndexPath *)idx inView:(UIView *)view中注释①描述:此方法会在保存时调用两次,idx所返回的数据除了我们选中的行,还会返回一个其他行。 若是采用这种方式映射唯一标识,会出现保存了我们不需要的行的标识,导致恢复滑动位置失效,针对此问题目前笔者尚未有答案,查阅资料发现这个问题曾经是苹果的一个BUG,若是大家知道具体原因,欢迎评论和补充。目前在此基础上笔者自己想的解决办法:定义_currentPath追踪当前选中的cell,保存时根据_currentPath保存我们需要的标识,测试中发现可以解决问题。
QIRestorationDemo地址

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容