管理View Controller以维护状态

时间:2018-03-12 19:34:11

标签: ios swift xcode viewcontroller

有关如何在视图控制器之间导航的基本问题。说我有VC" A"和VC" B"都嵌入在导航控制器中。从A到B,我使用了一个segue。在我到达B之后,我点击一个按钮进行一些视觉上的改变,比如按钮的颜色。然后我点击导航控制器的后退按钮取消,然后返回A.然后我再次使用segue转到B,我得到一个新的VC" B" - 没有新的按钮颜色。我想这就是segues的工作方式。

但是,如何使用新的按钮颜色获得相同的VC B?

我的hack是保存VC B的实例变量(在VC A&#39的类中),并使用navigationController.pushViewController()导航到它。测试证实我的按钮颜色更改仍然在B的调用之​​间。但是这个解决方案感觉笨拙和hacky。

所以,在我充实这个代码之前,我需要问一下:有没有设计模式可以进行A-> B-> A-> B而不是第二次获得新的B?什么是首选方法?

4 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:1)

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)
    }
}

答案 2 :(得分:1)

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

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

使用Singleton类的示例:

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)
   }
}

答案 3 :(得分:0)

可以使用“ navigationController”作为入口点在viewController之间进行选择,您可以从中选择到根VCA,然后到VCB。在这种情况下,会保留VC的所有状态(但我认为是陀螺仪和加速度计)。在我所有的应用程序中都可以正常工作,甚至那些使用场景动画的应用程序:-)

亚历克斯