管理视图控制器以维护状态



关于如何在视图控制器之间导航的基本问题。假设我有 VC"A"和 VC"B",两者都嵌入在导航控制器中。要从 A 到 B,我使用 segue。到达 B 后,我单击一个按钮,该按钮会进行一些视觉更改,例如按钮的颜色。然后我点击导航控制器的后退按钮放松,然后回到 A。然后我再次使用 segue 转到 B,我得到一个新的 vc "B" - 没有新的按钮颜色。我想这就是 segues 的工作方式。

但是,我如何获得具有新按钮颜色的相同VC B?

我的技巧是保存VC B的实例变量(在VC A的类中),并使用navigationController.pushViewController()导航到它。测试确认我的按钮颜色更改在调用 B 之间保持不变。但是这个解决方案感觉笨拙和笨拙。

因此,在我充实这段代码之前,我需要问:是否有一种设计模式可以使用 A->B->A->B 而不是第二次获得新的 B?首选方法是什么?

当您推送到视图控制器 B 时,将创建 B 的实例,这就是您推送到的内容。当您弹出回视图控制器 A 时,视图控制器 B 的该实例将被取消初始化,永远消失。当您推送回视图控制器 B 时,您将创建一个新实例。因此,要使按钮的颜色保持不变,您需要保留视图控制器 B 的状态,以便其所有实例都反映该更改。有多种方法可以保留状态,您选择的选项将由项目和个人偏好决定。

UINavigationController

解除分配弹出的视图控制器 (VC B),因此当您尝试再次推送 VC B 时,会创建一个新实例。除非您在VC A中强烈引用VC B。不建议这样做,但 VC A 保留在导航堆栈中,因此如果它包含对 VC B 的引用,则可以将该实例推回。

建议的方法是在弹出 VC B 时获取要维护的状态,并在推送新的 VC B 实例时将其设置回去。

解决方案 1(不推荐):

class VCA: UIViewController {
lazy var vcB: VCB = VCB()
func presentVCB() {
navigationController?.pushViewController(vcB, animated: true)
}
}
class VCB: UIViewController {
var someState: String = ""
}

解决方案 2,使用委派:

class VCA: UIViewController, VCBDelegate {
// This could be any data-structure in which you can store the states in VC B
var lastVCBState: String?
func presentVCB() {
let vcB: VCB = VCB()
vcB.delegate = self
lastVCBState != nil ? vcB.someState = lastVCBState! : ()
navigationController?.pushViewController(vcB, animated: true)
}
// MARK: VCBDelegate
func didPopWith(state: String) {
lastVCBState = state
}
}
protocol VCBDelegate: class {
func didPopWith(state: String)
}
class VCB: UIViewController {
weak var delegate: VCBDelegate?
// Any data-structure in which you can store the states
var someState: String = ""
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
delegate?.didPopWith(state: someState)
}
}

步骤1:当您更改底部的颜色时,请以任何持久的方式保存它。 例如,Singleton Class 或 NSUserDefaults。

步骤2:在VCB中加载保存的颜色。

使用单例类的示例:

class VCB: UIViewController {
@IBOutlet weak var myButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.myButton.backgroundColor = UIHelper.sharedInstance.VCBButtonColor
}
@IBAction func changeColorButtonAction(_ sender: UIButton) {
//Save in the color in singleton class
UIHelper.sharedInstance.VCBButtonColor = UIColor.green
}
}
//Singleton Class
class UIHelper: NSObject {
var VCBButtonColor = UIColor.red
static let sharedInstance = UIHelperClass()    
override init() {
...
}
}

注意:当您使用单例类并终止应用时,您将丢失保存的颜色。

使用用户默认值的示例:

class VCB: UIViewController {
@IBOutlet weak var myButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if let savedColor = UserDefaults.standard.color(forKey: "SavedColor") {
self.myButton.backgroundColor = savedColor
}
}
@IBAction func changeColorButtonAction(_ sender: UIButton) {
UserDefaults.standard.set(color: UIColor.red, forKey: "SavedColor")
}
}
extension UserDefaults {
func color(forKey key: String) -> UIColor? {
var color: UIColor?
if let colorData = data(forKey: key) {
color = NSKeyedUnarchiver.unarchiveObject(with: colorData) as? UIColor
}
return color
}
func set(color: UIColor?, forKey key: String) {
var colorData: NSData?
if let color = color {
colorData = NSKeyedArchiver.archivedData(withRootObject: color) as NSData?
}
set(colorData, forKey: key)
}
}

viewController之间的Segue可以使用"navigationController"作为入口点来完成,您可以从该入口点到根VCA,然后到VCB。在这种情况下,VC的所有状态都被保留(但我认为陀螺仪和加速度计)。这在我的所有应用程序中都运行良好,即使是那些使用场景动画的应用程序:-)

亚历克斯

最新更新