tl;dr 状态恢复过程似乎正在发生,但在恢复完成后,堆栈(非根)视图控制器不会在应用程序中结束。
我正在尝试在不使用任何 .nib 或情节提要的应用程序中实现状态恢复。这是一个相当基本的结构:窗口rootViewController
是UINavigationController
其自己的rootViewController
和所有其他子视图控制器UITableViewControllers
(例如,Window > Nav Ctrl > Table View Ctrl > Table View Ctrl > 等)。没有一个视图控制器是重复的(即堆栈上的每个项目都是一个不同的UITableViewController
子类)
由于我没有使用情节提要创建视图控制器,因此我为每个视图控制器类设置了指定的初始化程序restorationIdentifier
和restorationClass
.
当应用程序正在恢复时,我看到应用程序进入后台时存在的每个视图控制器(例如,导航控制器、播客列表控制器和播客详细信息控制器)都发生了解码,但最终结果是恢复始终是导航控制器与其正常的根视图控制器(播客列表控制器)一起显示。
这个问题似乎与这个问题非常相似,但我肯定会在我的视图控制器(如果存在)上调用super
-encode
和decodeRestorableStateWithCoder:
方法,因此该解决方案对我没有帮助。
我观看了 WWDC 视频并阅读了许多教程,虽然我似乎满足了所有要求,但有些事情并没有按应有的方式工作。
我唯一能想到的就是恢复正在发生,但我的默认初始化代码是将恢复的导航视图控制器堆栈替换为仅包含根的“新”堆栈。根据 WWDC 视频,窗口和根视图控制器应在状态恢复之前正常设置,并且不应影响恢复后的最终应用状态。
我想对我来说一个问号是viewControllerWithRestorationIdentifierPath:
我的UINavigationController
. 应该rootViewController
像我一样设置吗?如果没有,还会发生什么?我实际上找不到任何工作示例代码,其中导航控制器正在恢复并且它不是从笔尖或情节提要创建的。除此之外,我很难过。
实现代码
FLAppDelegate.m
# pragma mark - UIApplicationDelegate
# pragma mark Monitoring App State Changes
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Window and root VC set up in window getter
[self.window makeKeyAndVisible];
return YES;
}
# pragma mark Managing App State Restoration
- (BOOL)application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder {
return YES;
}
- (BOOL)application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder {
return YES;
}
#pragma mark Providing a Window for Storyboarding
- (UIWindow *)window {
if (!_window) {
_window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
_window.rootViewController = self.navigationController;
}
return _window;
}
- (FLNavigationController *)navigationController {
if (!_navigationController) {
FLPodcastTableViewController* podcastViewController = [[FLPodcastTableViewController alloc] initWithStyle:UITableViewStylePlain];
_navigationController = [[FLNavigationController alloc] initWithRootViewController:podcastViewController];
}
return _navigationController;
}
FLNavigationController.m
- (id)initWithRootViewController:(UIViewController *)rootViewController {
self = [super initWithRootViewController:rootViewController];
if (self) {
self.restorationIdentifier = @"FLNavigationController";
self.restorationClass = self.class;
}
return self;
}
#pragma mark - UIViewControllerRestoration
+ (UIViewController *)viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder {
FLPodcastTableViewController* podcastViewController = [[FLPodcastTableViewController alloc] initWithStyle:UITableViewStylePlain];
return [[self alloc] initWithRootViewController:podcastViewController];
}
FLPodcastTableViewController.m
- (id)initWithStyle:(UITableViewStyle)style {
self = [super initWithStyle:style];
if (self) {
[self.tableView registerClass:FLPodcastTableViewCell.class forCellReuseIdentifier:FLPodcastTableViewCellIdentifier];
self.restorationIdentifier = @"FLPodcastTableViewController";
self.restorationClass = self.class;
}
return self;
}
#pragma mark - UIViewControllerRestoration
+ (UIViewController *)viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder {
return [[self alloc] initWithStyle:UITableViewStylePlain];
}
FLPodcastEpisodeTableViewController.m
- (id)initWithPodcast:(FLPodcast *)podcast {
self = [self initWithStyle:UITableViewStylePlain];
if (self) {
self.podcast = podcast;
self.restorationIdentifier = @"FLPodcastEpisodeTableViewController";
self.restorationClass = self.class;
[self.tableView registerClass:FLPodcastEpisodeTableViewCell.class forCellReuseIdentifier:FLPodcastEpisodeTableViewCellIdentifier];
}
return self;
}
#pragma mark - UIViewControllerRestoration
+ (UIViewController *)viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder {
FLPodcastEpisodeTableViewController* viewController = nil;
NSString* podcastURI = [coder decodeObjectForKey:kPodcastURLKey];
NSURL* podcastURL = [NSURL URLWithString:podcastURI];
FLPodcast* podcast = [FLPodcast podcastWithURL:podcastURL];
if (podcast) {
viewController = [[self alloc] initWithPodcast:podcast];
}
return viewController;
}
- (void)encodeRestorableStateWithCoder:(NSCoder *)coder {
[coder encodeObject:self.podcast.feedURL.absoluteString forKey:@kPodcastURLKey];
[super encodeRestorableStateWithCoder:coder];
}
- (void)decodeRestorableStateWithCoder:(NSCoder *)coder {
[super decodeRestorableStateWithCoder:coder];
}