UIViewControllers 正在创建但未在状态恢复中显示

Posted

技术标签:

【中文标题】UIViewControllers 正在创建但未在状态恢复中显示【英文标题】:UIViewControllers being created but not shown in state restoration 【发布时间】:2014-02-13 23:02:54 【问题描述】:

我的应用在状态恢复时无法正常工作。以前是这样,但是当我开始离开情节提要时,它就停止了。

我的应用以 LoginViewController 开头,这是我故事板中的起始视图控制器。如果登录成功,则尝试将两个FolderViewController 添加到导航控制器。这样可见文件夹已经深了一层。这是在以下代码中完成的:

UINavigationController  *foldersController = [[UINavigationController alloc] initWithNavigationBarClass:nil toolbarClass:nil];
foldersController.restorationIdentifier = @"FolderNavigationController";

FolderViewController *root = [storyboard instantiateViewControllerWithIdentifier:@"FolderView"];
root.folderId = 0;
FolderViewController *fvc = [storyboard instantiateViewControllerWithIdentifier:@"FolderView"];
fvc.folderId = 1;

[foldersController setViewControllers:@[root, fvc] animated:YES];
[self presentViewController:foldersController animated:YES completion:nil];

FolderViewController 有这个awakeFromNib

- (void)awakeFromNib

    [super awakeFromNib];
    self.restorationClass = [self class];   // If we don't have this, then viewControllerWithRestorationIdentifierPath won't be called.

在故事板中,FolderViewController 有一个restorationIdentifier 集。当我按下主页按钮时,应用程序被暂停。我在FolderViewController 的恢复电话正在被调用:

// This is being called
- (void)encodeRestorableStateWithCoder:(NSCoder *)coder

    [super encodeRestorableStateWithCoder:coder];
    [coder encodeInt64:self.folderId forKey:@"folderId"];

现在的问题是当我尝试恢复时。我在调试器中停止应用程序,然后重新启动它。这将启动恢复过程。

首先,我的viewControllerWithRestorationIdentifierPath:coder: 和我的LoginViewController 被调用。这并没有多大作用,它的使用是可选的。我试过删除它,我没有任何不良影响。

+ (UIViewController*) viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder

    LoginViewController* vc;
    UIStoryboard* sb = [coder decodeObjectForKey:UIStateRestorationViewControllerStoryboardKey];
    if (sb)
    
        vc = (LoginViewController *)[sb instantiateViewControllerWithIdentifier:@"LoginViewController"];
        vc.restorationIdentifier = [identifierComponents lastObject];
        vc.restorationClass = [LoginViewController class];
    
    return vc;

接下来,我的FolderViewControllerviewControllerWithRestorationIdentifierPath:coder: 被调用:

// This is being called
+ (UIViewController*) viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder

    FolderViewController* vc;
    UIStoryboard* sb = [coder decodeObjectForKey:UIStateRestorationViewControllerStoryboardKey];
    if (sb)
    
        vc = (FolderViewController *)[sb instantiateViewControllerWithIdentifier:@"FolderView"];
        vc.restorationIdentifier = [identifierComponents lastObject];
        vc.restorationClass = [FolderViewController class];
        vc.folderId = [coder decodeInt32ForKey:@"folderId"];
    
    return vc;

我之前也有一个decodeRestorableStateWithCoder:,它确实被调用了。但是,由于它是在 viewControllerWithRestorationIdentifierPath:coder: 中设置的,因此没有必要保留它。

所有这些东西都被调用了适当的次数。但最后,在LoginViewController 中显示的唯一视图控制器。为什么我的FolderViewControllers 没有显示。我需要在我的LoginViewController 中进行设置以附加我之前手动添加的视图控制器吗?

编辑

在阅读了似乎相关的 http://aplus.rs/2013/state-restoration-for-modal-view-controllers/ 之后,我将以下代码添加到 App 委托:

- (UIViewController *)application:(UIApplication *)application viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder

    if ([identifierComponents.lastObject isEqualToString:@"FolderNavigationController"])
    
        UINavigationController *nc = [[UINavigationController alloc] init];
        nc.restorationIdentifier = @"FolderNavigationController";
        return nc;
    
    else
        return nil;

我认为应用程序现在更快乐了,但它仍然无法正常恢复。现在我的日志中出现了这个错误:

警告:尝试在视图不在窗口层次结构中的 上呈现

这是不同的东西。

【问题讨论】:

你有没有解决这个问题。我有类似的问题,我有一个自定义选项卡,它添加了包含在导航控制器中的 childviewcontrollers,当我打印它提供正确的路径时,但不会恢复到推送的控制器,尽管它通过编码保存到自定义选项卡索引和 childviewcontroller... 【参考方案1】:

我有类似的问题。我的视图控制器堆栈非常简单:带有表格视图的根视图 -> 一些详细信息视图 -> 一些编辑详细信息视图。没有导航视图,视图是模态的。它没有用。

原来,问题在于,根视图控制器中的 viewControllerWithRestorationIdentifierPath() 应该如下所示:

+ (UIViewController *) viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents
                                                             coder:(NSCoder *)coder

        NSDictionary *myRestorableObj = [coder decodeObjectForKey:@"myRestorableObj"];

        // @todo Add more sanity checks for internal structures of @ myRestorableObj here
        if (myRestorableObj == nil)
                return nil;

        return [[UIApplication sharedApplication] delegate].window.rootViewController;

实例化新的根视图控制器是错误的。它创建了新的视图控制器堆栈,堆栈中存储的子视图控制器不属于这些堆栈。

所有其他子视图控制器都应该像往常一样创建,使用以下代码:

UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"MyChildViewController"];

希望这会有所帮助。

【讨论】:

【参考方案2】:

您需要为不同的FolderViewController 对象分配不同的恢复标识符。

例如:

FolderViewController *folderViewController1 = // initialize object ;
FolderViewController *folderViewController2 = // initialize object ;

folderViewController1. restorationIdentifier = @"folderViewController1";
folderViewController2. restorationIdentifier = @"folderViewController2";

我试过上面的代码,效果很好。

【讨论】:

好吧,我认为这是错误的,restore id 在这里无关紧要。答案在上面。

以上是关于UIViewControllers 正在创建但未在状态恢复中显示的主要内容,如果未能解决你的问题,请参考以下文章

热代码修复正在编译但未在 grails 2.4.4 中选择

AWS SNS - 推送 GCM 显示为从 Cloudwatch 发送但未在移动设备中接收

history.push 正在更改 url 但未在反应中呈现组件

webview 正在模拟器中加载,但未在设备中加载

Firebase Auth iOS用户匿名创建但未在控制台中显示

ubuntu中Docker 容器正在运行,但未在 docker ps 中显示