首页 > 解决方案 > 查看其他 ViewController 后,用户输入数据不会保留

问题描述

用户输入输入到 ViewController1 上的 TextFields 和 TextViews 中,但是当我选择一个按钮以通过 segue 显示 ViewController2 或 ViewController3 时,在我返回 ViewController1(也通过另一个 segue)时,输入不再存在,好像该应用程序刚刚重新打开。当用户切换到不同的视图时,如何让初始用户输入保留在文本字段和文本视图中,直到用户点击 ViewController1 上的“发送电子邮件”按钮?

下面是我的代码

视图控制器1

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var DateTextField: UITextField!
    @IBOutlet weak var ScrollView: UIScrollView!
    @IBOutlet weak var FirstTextView: UITextField!
    @IBOutlet weak var FirstName: UITextField!
    @IBOutlet weak var OtherDetailsField: UITextView!

    lazy var datePicker: UIDatePicker = {
        let picker = UIDatePicker()
        picker.datePickerMode = .date
        picker.addTarget(self, action: #selector(datePickerChanged(_:)), for: .valueChanged)
        return picker
    }()
    lazy var dateFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateStyle = .medium
        formatter.timeStyle = .none
        return formatter
    }()

    // Adjust Scroll for Keyboard ------------------
    @objc func adjustForKeyboard(notification: Notification) {
        guard let keyboardValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }
        let keyboardScreenEndFrame = keyboardValue.cgRectValue
        let keyboardViewEndFrame = view.convert(keyboardScreenEndFrame, from: view.window)
        if notification.name == UIResponder.keyboardWillHideNotification {
            ScrollView.contentInset = .zero
        } else {
            ScrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardViewEndFrame.height - view.safeAreaInsets.bottom, right: 0)
        }
        ScrollView.scrollIndicatorInsets = ScrollView.contentInset
      //  let selectedRange = OtherDetailsField.selectedRange
      //  OtherDetailsField.scrollRangeToVisible(selectedRange)
    }

    override func viewDidLoad(){
        super.viewDidLoad()

        // Adjust Scroll for Keyboard ---------------
        let notificationCenter = NotificationCenter.default
        notificationCenter.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillHideNotification, object: nil)
        notificationCenter.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)

        // Date Picker ---------------
        DateTextField.inputView = datePicker}
    @objc func datePickerChanged(_ sender: UIDatePicker){
        DateTextField.text = dateFormatter.string(from: sender.date)
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?){view.endEditing(true)
    }

    // Dismiss Keyboard ------------------
    func setupKeyboardDismissRecognizer(){
        let tapRecognizer: UITapGestureRecognizer = UITapGestureRecognizer(
            target: self, action: #selector(ViewController.dismissKeyboard))
        tapRecognizer.cancelsTouchesInView = false
        self.view.addGestureRecognizer(tapRecognizer)
    }

    @objc func dismissKeyboard() {
        view.endEditing(true)
    }
}

// Add Done Button to keypad toolbar -----------------
extension UITextField{

    @IBInspectable var doneAccessory: Bool{
        get{
            return self.doneAccessory
        }
        set (hasDone) {
            if hasDone{
                addDoneButtonOnKeyboard()
            }
        }
    }

    func addDoneButtonOnKeyboard() {
        let doneToolbar: UIToolbar = UIToolbar(frame: CGRect.init(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
        doneToolbar.barStyle = .default

        let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        let done: UIBarButtonItem = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(self.doneButtonAction))

        let items = [flexSpace, done]
        doneToolbar.items = items
        doneToolbar.sizeToFit()

        self.inputAccessoryView = doneToolbar
    }

    @objc func doneButtonAction()
    {
        self.resignFirstResponder()
    }
}
extension UITextView{

    @IBInspectable var doneAccessory: Bool{
        get{
            return self.doneAccessory
        }
        set (hasDone) {
            if hasDone{
                addDoneButtonOnKeyboard()
            }
        }
    }

    func addDoneButtonOnKeyboard() {
        let doneToolbar: UIToolbar = UIToolbar(frame: CGRect.init(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
        doneToolbar.barStyle = .default

        let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        let done: UIBarButtonItem = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(self.doneButtonAction))

        let items = [flexSpace, done]
        doneToolbar.items = items
        doneToolbar.sizeToFit()

        self.inputAccessoryView = doneToolbar
    }

    @objc func doneButtonAction() {
        self.resignFirstResponder()
    }
}

视图控制器2

import UIKit

class ViewController2: UIViewController {

    @IBOutlet weak var ScrollView: UIScrollView!

    // Adjust Scroll for Keyboard ------------------
    @objc func adjustForKeyboard(notification: Notification) {
        guard let keyboardValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }
        let keyboardScreenEndFrame = keyboardValue.cgRectValue
        let keyboardViewEndFrame = view.convert(keyboardScreenEndFrame, from: view.window)

        if notification.name == UIResponder.keyboardWillHideNotification {
            ScrollView.contentInset = .zero
        } else {
            ScrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardViewEndFrame.height - view.safeAreaInsets.bottom, right: 0)
        }
        ScrollView.scrollIndicatorInsets = ScrollView.contentInset
        //let selectedRange = yourTextView.selectedRange
        //yourTextView.scrollRangeToVisible(selectedRange)
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // Adjust Scroll for Keyboard ---------------
        let notificationCenter = NotificationCenter.default
        notificationCenter.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillHideNotification, object: nil)
        notificationCenter.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
    }

        // Dismiss Keyboard ------------------
        func setupKeyboardDismissRecognizer(){
            let tapRecognizer: UITapGestureRecognizer = UITapGestureRecognizer(
                target: self, action: #selector(ViewController.dismissKeyboard))
            tapRecognizer.cancelsTouchesInView = false
            self.view.addGestureRecognizer(tapRecognizer)
        }
        func dismissKeyboard()
        {
            view.endEditing(true)
        }
    }

视图控制器3

import UIKit

class ViewController3: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

标签: iosswiftxcodeswift5

解决方案


简短回答:您使用创建新实例的反向搜索,您可以使用“解雇”方法或使用标签栏控制器。


长答案:

  • 首先,我假设您在 Xcode 中创建项目时创建了单视图控制器,并且您使用的所有 segues 都是“显示”类型。
  • 假设您创建 segue 'ViewController1->ViewController2' 和按钮 'NEXT' 来执行它。
  • 当您单击“下一步”时,您创建了一个新的 ViewController2 实例,有点像“新副本”。
  • 接下来,您创建另一个 segue 以返回:“ViewController2->ViewController1”和按钮“BACK”执行。
  • 当您单击“返回”按钮(触发 segue)时,您不会回到原来的 ViewController1,但您正在创建 ViewController1 的新实例。
  • 如您所见,以这种方式使用 segues 可能会在用户可以来回移动时产生未来的内存问题,每次创建新实例,将窗口堆叠在一起。

    最简单的解决方案是删除向后指向的segues,而是将'dismiss'方法放在'BACK'按钮代码块中:

        self.dismiss(animated: true, completion: nil)
    

    每次使用“dismiss”方法时,都会关闭实际的 ViewController 并返回上一个。
    如果您希望“HOME”按钮之类的东西从任何 ViewController 回到第一个(根),您可以使用以下代码:

        self.view.window!.rootViewController?.dismiss(animated: true,completion: nil)
    

    但请记住 - 如果您在关闭之前不编写一些代码来保存您的数据,当您关闭它们时,您仍然会丢失 ViewController2 和 ViewController3 数据。

    最后,如果您需要在用户在 ViewController 之间切换时显示您的数据,我会使用Tab bar controller。您可以在创建 Xcode 项目时使用模板“Tabbed App”创建它。



    希望这可以帮助!不要把它当作 100%,我仍然是一个 Swift Rookie :)


  • 推荐阅读