iOS状态保存和容器视图

Dav*_*eck 19 iphone ios uikit-state-preservation

我在故事板中有一个使用容器视图的视图控制器.两者都具有恢复标识符集.父母正在被保存并恢复正常.然而,孩子不是.在子视图控制器上都没有-encodeRestorableStateWithCoder:-decodeRestorableStateWithCoder:正在被调用.

保存使用视图容器创建的子视图控制器的正确方法是什么?我可以将子视图控制器保存在父节点中-encodeRestorableStateWithCoder:,这将导致它被保存,但我没有办法在恢复期间使用它.

Sla*_*lav 20

容器视图控制器" 不会自动保存对任何包含的子视图控制器的引用.如果要实现自定义容器视图控制器,则必须自己编码子视图控制器对象(如果要保留它们) ".

我发现有简单的规则:

1.已经创建了嵌入式(子)视图控制器,并在状态保存过程中添加到父视图控制器.因此,如果您使用storyboard,则不必执行任何操作,否则您必须实例化子视图控制器并手动添加它:

-(void)viewDidLoad
{
    [super viewDidLoad];
    NSLog(@"Did load");
    MyChildViewController *childViewController = [MyChildViewController new];
    [self addChildViewController:childViewController];
    [childViewController didMoveToParentViewController:self];
    self.childVC = childViewController;
}
Run Code Online (Sandbox Code Playgroud)

您可以在-viewDidLoad以后添加子视图.使用self.childVC.view.frame = [self frameForChildController]; [self.view addSubview:self.childVC.view];此.

2.您不需要将父视图控制器保存在父亲-encodeRestorableStateWithCoder:自己中,但您应该使用编码对该对象的引用-encodeObject:forKey:.如果你有参考,你可以这样做:

-(void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
    NSLog(@"Encode");
    UIViewController *childViewController = self.childVC;
    [coder encodeObject:childViewController forKey:@"ChildVC"];
    [super encodeRestorableStateWithCoder:coder];
}
Run Code Online (Sandbox Code Playgroud)

如果您使用Storyboard,请参阅/sf/answers/929579241/以获取对子VC的引用.或者你可以写一些简单的东西:

-(void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
    NSLog(@"Encode");
    UIViewController *childViewController = [self.childViewControllers objectAtIndex:0]; //[self.childViewControllers lastObject];
    [coder encodeObject:childViewController forKey:@"ChildVC"];
    [super encodeRestorableStateWithCoder:coder];
}
Run Code Online (Sandbox Code Playgroud)

3. 应在状态恢复过程中创建嵌入式(子)视图控制器并将其添加到父视图控制器.所以,如果你在第一段中做了所有事情,那么这里没有更多的事要做了.

4."但是,在这种情况下,我们不解码子视图控制器.我们可以,但实际上我们不需要它.MyChildViewController对象将恢复其自己的状态.我们只编码此引用以获取运行时将链向下走到MyChildViewController实例并对其进行保存和恢复".

-(void)decodeRestorableStateWithCoder:(NSCoder *)coder
{
    NSLog(@"Decode");
    [super decodeRestorableStateWithCoder:coder];
}
Run Code Online (Sandbox Code Playgroud)

本书帮助我理解状态保存与容器的观点.还要为本书寻找一个好例子

  • 总结一下,如果您使用情节提要容器视图(带有嵌入segue的视图),那么您要做的就是用来自父级的`encodeRestorableStateWithCoder:`中的一个孩子调用`encodeObject:forKey:`。获取对孩子的引用的最佳方法是在“ prepareForSegue:sender:”中获取嵌入的segue。无需手动解码子项,因为还原过程将找到已存在的子项并从存档中还原其状态。但是,如果您不使用情节提要(即手动添加子级),则可能还需要实现该查找机制。 (2认同)

Sta*_*lov -1

我认为答案就在文档中 ,据说:

“ UIViewController 类保存对所呈现的视图控制器和用于创建视图控制器的故事板(如果有)的引用。视图控制器还要求其视图层次结构中的视图保存任何相关信息。但是,此类不会自动保存对任何包含的子视图控制器的引用。如果您正在实现自定义容器视图控制器,则如果您希望保留子视图控制器对象,则必须自己对它们进行编码。

所以你可以这样做:

-(void)encodeRestorableStateWithCoder:(NSCoder *)coder {
    [super encodeRestorableStateWithCoder:coder];
    [self.myChildViewController encodeRestorableStateWithCoder:coder];
}

-(void)decodeRestorableStateWithCoder:(NSCoder *)coder {
    [super decodeRestorableStateWithCoder:coder];
    [self.myChildViewController decodeRestorableStateWithCoder:coder];
}
Run Code Online (Sandbox Code Playgroud)

并且在 MyChildViewController 中不要调用 super :)

  • 该解决方案实际上并不使用子级的状态保存/恢复机制,它只是调用一些自定义代码(您误导性地称为encodeRestorableStateWithCoder和decodeRestorableStateWithCoder)来保存和恢复其状态作为父级状态的一部分。 (2认同)