无法使State Restoration与Programmatic Navigation Controller配合使用

时间:2017-08-21 07:36:39

标签: ios swift uinavigationcontroller programmatically-created state-restoration

我无法让状态恢复与导航控制器一起工作。我正在使用Swift并且不想使用Storyboard(Programmatic)。我在网上找到的几乎所有帮助都不在Swift或使用Storyboard。

在下面的演示代码中,ViewController包含一个简单的PickerView,selection变量跟踪Picker选择。 AppDelegate提供2个选项。使用选项1 ,不使用导航控制器,并且Picker的状态可以正常恢复,但不会使用选项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,更改Picker后跟 cmd-Shift-H 会导致selection变量保存在{{ 1}}。然后,我单击Xco​​de 停止按钮,然后再次运行它,encodeRestorableState变量将在selection中恢复。相比之下,选项2 状态恢复不起作用,因为永远不会调用decodeRestorableState,因此不会恢复decodeRestorableState变量。但是,selection处的断点显示viewDidAppear =“PickerNav”和navigationController?.restorationIdentifier =“PickerVC”

根据我的阅读,我怀疑我可能需要在AppDelegate中使用restorationIdentifier,但我不知道如何正确使用它。我在AppDelegate底部的尝试(代码被注释掉)导致应用程序崩溃。

1 个答案:

答案 0 :(得分:1)

您可以向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类中添加此代码,并删除您在viewControllerWithRestorationIdentifierPath

中添加的AppDelegate方法