I am working with MacCatalyst and I would like to restore the previous content of windows after reopening the app. I found an example project (https://developer.apple.com/documentation/uikit/uiscenedelegate/restoring_your_app_s_state). I adopted the stateRestorationActivity(for scene: UIScene) method, however, according to the example project, when I want to configure a scene in the scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) method based on the session.stateRestorationActivity, the variable is always nil. Here's my code:
In SceneDelegate:
func stateRestorationActivity(for scene: UIScene) -> NSUserActivity? {
return scene.userActivity
}
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
#if targetEnvironment(macCatalyst)
if let titlebar = windowScene.titlebar {
titlebar.titleVisibility = .hidden
titlebar.toolbarStyle = .unified
}
#endif
window = UIWindow(frame: windowScene.coordinateSpace.bounds)
window?.windowScene = windowScene
let contentViewController = ContentViewController()
window?.rootViewController = UINavigationController(rootViewController: contentViewController)
window?.makeKeyAndVisible()
if let userActivity = connectionOptions.userActivities.first ?? session.stateRestorationActivity {
if !configure(window: window, with: userActivity) {
print("Failed to restore from \(userActivity)")
}
} else {
if !configure(window: window, with: ContentType.Inbox.openDetailUserActivity) {
}
}
}
In AppDelegate:
func application(_ application: UIApplication, shouldSaveSecureApplicationState coder: NSCoder) -> Bool {
return true
}
func application(_ application: UIApplication, shouldRestoreSecureApplicationState coder: NSCoder) -> Bool {
return true
}
// MARK: - UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
var configurationName: String!
switch options.userActivities.first?.activityType {
case .UserActivity.SystemActivityType, .UserActivity.TagActivityType, .UserActivity.ProjectActivityType:
configurationName = "Detail Configuration"
default:
configurationName = "Default Configuration"
}
return UISceneConfiguration(name: configurationName, sessionRole: connectingSceneSession.role)
}
I registred different configurations of UISceneSessions in the info plist.
Looks like you need to assign a
NSUserActivityto the correctUIWindowSceneproperty with your view controller'sviewWillAppearmethod, then in theviewWillDisappearassignnilto that property.Make sure to assign it to the
UIViewControllerthat is therootViewControllerfor theUIWindowbeing shown. Meaning, if you have aUINavigationControlleras the parent, usenavigationController?.view.window?.windowScene?.userActivity.A code example is available, not mine, but a helpful one.
It seems like the state restoration subsystem takes the user activity from any view controllers of active scenes and stores the state from it, which makes sense.
Also, make sure to store your information in
NSUserActivity.userInfo.More details available on my blog as well.