无法让状态恢复与程序化导航控制器一起使用
Can't get State Restoration to work with Programmatic Navigation Controller
我无法使用导航控制器进行状态恢复。我正在使用 Swift 并且不想使用故事板(程序化)。我在网上找到的几乎所有帮助都没有 Swift 或使用 Storyboards。
在下面的演示代码中,ViewController 包含一个简单的 PickerView,并且一个 selection
变量跟踪 Picker 选择。 AppDelegate 有 2 个选项。使用 选项 1,不使用导航控制器并且选择器的状态恢复正常,但使用 选项 2 中的导航控制器则不会恢复. (在下面的代码中,选项 1 被注释掉,选项 2 处于活动状态)。
您可以将下面的代码复制并粘贴到一个新的 singleView 应用程序中,它应该会重现我所描述的内容。 (我测试过了)
AppDelegate 代码:
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, shouldSaveApplicationState coder: NSCoder) -> Bool {
return true
}
func application(_ application: UIApplication, shouldRestoreApplicationState coder: NSCoder) -> Bool {
return true
}
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
let pickerVC = ViewController()
//Option 1: No NavC used
//window?.rootViewController = pickerVC
//Option 2: NavC used
let navC = UINavigationController(rootViewController: pickerVC)
navC.restorationIdentifier = "PickerNav"
window?.rootViewController = navC
return true
}
// func application(_ application: UIApplication, viewControllerWithRestorationIdentifierPath identifierComponents: [Any], coder: NSCoder) -> UIViewController? {
// let storyboard = UIStoryboard(name: "Main", bundle: nil)
// if let lastItem = identifierComponents.last as? String {
// return storyboard.instantiateViewController(withIdentifier: lastItem)
// }
// return nil
// }
}
ViewController代码:
import UIKit
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
var pickerView: UIPickerView!
var selection = 0
let group = ["Fruit","Vegetable","Meat","Bread"]
override func viewDidLoad() {
super.viewDidLoad()
restorationIdentifier = "PickerVC"
setupPicker()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
pickerView.selectRow(selection, inComponent: 0, animated: false)
}
override func encodeRestorableState(with coder: NSCoder) {
coder.encode(selection, forKey: "selection")
super.encodeRestorableState(with: coder)
}
override func decodeRestorableState(with coder: NSCoder) {
selection = coder.decodeInteger(forKey: "selection")
super.decodeRestorableState(with: coder)
}
func setupPicker() {
pickerView = UIPickerView()
pickerView.delegate = self
pickerView.dataSource = self
view.addSubview(pickerView)
pickerView.translatesAutoresizingMaskIntoConstraints = false
pickerView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
pickerView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor).isActive = true
pickerView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
pickerView.heightAnchor.constraint(equalToConstant: 300).isActive = true
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return group.count
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
selection = pickerView.selectedRow(inComponent: 0)
}
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
let pickerLabel = UILabel()
pickerLabel.font = UIFont.systemFont(ofSize: 26)
pickerLabel.textAlignment = .center
pickerLabel.text = group[row]
pickerLabel.textColor = .white
return pickerLabel
}
}
我的测试详情: 使用选项 1,更改选择器然后 cmd-Shift-H 会导致 selection
变量保存在 encodeRestorableState
中。然后我单击 Xcode 停止 按钮,然后再次 运行 它,并且 selection
变量在 decodeRestorableState
中恢复。相比之下,选项 2
状态恢复不起作用,因为 decodeRestorableState
从未被调用,因此 selection
变量未恢复。但是,viewDidAppear
处的断点显示 navigationController?.restorationIdentifier
= "PickerNav" 和 restorationIdentifier
= "PickerVC"
根据我的阅读,我怀疑我可能需要在 AppDelegate 中使用 viewControllerWithRestorationIdentifierPath
,但我不知道如何正确使用它。我在 AppDelegate 底部的尝试(代码被注释掉)导致应用程序崩溃。
您可以为您的 ViewController 添加扩展并使其符合协议 UIViewControllerRestoration
并实现 viewControllerWithRestorationIdentifierPath
方法。
在 ViewController
的 viewDidLoad
函数中添加 restorationClass
就像 restorationIdentifer
就像
override func viewDidLoad() {
super.viewDidLoad()
restorationIdentifier = "PickerVC"
restorationClass = ViewController.self
setupPicker()
}
extension ViewController: UIViewControllerRestoration {
static func viewController(withRestorationIdentifierPath identifierComponents: [Any], coder: NSCoder) -> UIViewController? {
let vc = ViewController()
return vc
}
}
在您的 ViewController class 中添加此代码并删除您在 AppDelegate
中添加的 viewControllerWithRestorationIdentifierPath
方法
我无法使用导航控制器进行状态恢复。我正在使用 Swift 并且不想使用故事板(程序化)。我在网上找到的几乎所有帮助都没有 Swift 或使用 Storyboards。
在下面的演示代码中,ViewController 包含一个简单的 PickerView,并且一个 selection
变量跟踪 Picker 选择。 AppDelegate 有 2 个选项。使用 选项 1,不使用导航控制器并且选择器的状态恢复正常,但使用 选项 2 中的导航控制器则不会恢复. (在下面的代码中,选项 1 被注释掉,选项 2 处于活动状态)。
您可以将下面的代码复制并粘贴到一个新的 singleView 应用程序中,它应该会重现我所描述的内容。 (我测试过了)
AppDelegate 代码:
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, shouldSaveApplicationState coder: NSCoder) -> Bool {
return true
}
func application(_ application: UIApplication, shouldRestoreApplicationState coder: NSCoder) -> Bool {
return true
}
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
let pickerVC = ViewController()
//Option 1: No NavC used
//window?.rootViewController = pickerVC
//Option 2: NavC used
let navC = UINavigationController(rootViewController: pickerVC)
navC.restorationIdentifier = "PickerNav"
window?.rootViewController = navC
return true
}
// func application(_ application: UIApplication, viewControllerWithRestorationIdentifierPath identifierComponents: [Any], coder: NSCoder) -> UIViewController? {
// let storyboard = UIStoryboard(name: "Main", bundle: nil)
// if let lastItem = identifierComponents.last as? String {
// return storyboard.instantiateViewController(withIdentifier: lastItem)
// }
// return nil
// }
}
ViewController代码:
import UIKit
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
var pickerView: UIPickerView!
var selection = 0
let group = ["Fruit","Vegetable","Meat","Bread"]
override func viewDidLoad() {
super.viewDidLoad()
restorationIdentifier = "PickerVC"
setupPicker()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
pickerView.selectRow(selection, inComponent: 0, animated: false)
}
override func encodeRestorableState(with coder: NSCoder) {
coder.encode(selection, forKey: "selection")
super.encodeRestorableState(with: coder)
}
override func decodeRestorableState(with coder: NSCoder) {
selection = coder.decodeInteger(forKey: "selection")
super.decodeRestorableState(with: coder)
}
func setupPicker() {
pickerView = UIPickerView()
pickerView.delegate = self
pickerView.dataSource = self
view.addSubview(pickerView)
pickerView.translatesAutoresizingMaskIntoConstraints = false
pickerView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
pickerView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor).isActive = true
pickerView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
pickerView.heightAnchor.constraint(equalToConstant: 300).isActive = true
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return group.count
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
selection = pickerView.selectedRow(inComponent: 0)
}
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
let pickerLabel = UILabel()
pickerLabel.font = UIFont.systemFont(ofSize: 26)
pickerLabel.textAlignment = .center
pickerLabel.text = group[row]
pickerLabel.textColor = .white
return pickerLabel
}
}
我的测试详情: 使用选项 1,更改选择器然后 cmd-Shift-H 会导致 selection
变量保存在 encodeRestorableState
中。然后我单击 Xcode 停止 按钮,然后再次 运行 它,并且 selection
变量在 decodeRestorableState
中恢复。相比之下,选项 2
状态恢复不起作用,因为 decodeRestorableState
从未被调用,因此 selection
变量未恢复。但是,viewDidAppear
处的断点显示 navigationController?.restorationIdentifier
= "PickerNav" 和 restorationIdentifier
= "PickerVC"
根据我的阅读,我怀疑我可能需要在 AppDelegate 中使用 viewControllerWithRestorationIdentifierPath
,但我不知道如何正确使用它。我在 AppDelegate 底部的尝试(代码被注释掉)导致应用程序崩溃。
您可以为您的 ViewController 添加扩展并使其符合协议 UIViewControllerRestoration
并实现 viewControllerWithRestorationIdentifierPath
方法。
在 ViewController
的 viewDidLoad
函数中添加 restorationClass
就像 restorationIdentifer
就像
override func viewDidLoad() {
super.viewDidLoad()
restorationIdentifier = "PickerVC"
restorationClass = ViewController.self
setupPicker()
}
extension ViewController: UIViewControllerRestoration {
static func viewController(withRestorationIdentifierPath identifierComponents: [Any], coder: NSCoder) -> UIViewController? {
let vc = ViewController()
return vc
}
}
在您的 ViewController class 中添加此代码并删除您在 AppDelegate
viewControllerWithRestorationIdentifierPath
方法