简体   繁体   中英

Why do my properties and outlets become nil after performing a segue?

I am learning Swift and currently using two ViewControllers in a project. The first controller initializes data and performs a segue to the second. The second ViewController adds a new value to a variable passed in from the first ViewController. However, when I dismiss the segue and try to update the first one, all IBOutlet properties and variables suddenly become nil. This was derived by logging properties in the updateViewController() method of the firstViewController. Thank you in advance.

First ViewController

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {


    // Date Label
    @IBOutlet weak var dateLabel: UILabel!

    // Progress Bar
    @IBOutlet weak var progressBar: UIProgressView?

    // Progress Label
    @IBOutlet weak var progressLabel: UILabel!

    // Button Collection View
    @IBOutlet weak var collectionView: UICollectionView!

    // Current goal button
    @IBOutlet weak var currentGoal: UIButton!

    // Goal label
    @IBOutlet weak var goalLabel: UILabel!

    // Variable Initialization

    // Initialize daily water goal
    var dailyGoal = Float(20)

    // Initialize current progress
    var currentProgress = Float()

    // Water counter variable
    var waterDrank = Float(0)

    var percentageProgress = Float(0.0)

    override func viewDidLoad() {
        super.viewDidLoad()

    progressBar?.setProgress(0.0, animated: false)
        progressBar!.transform = progressBar!.transform.scaledBy(x: 1, y: 3)

    }

    // MARK: - Button & Progress View Logic

    func addProgress(amount: Float) {

        // Add amount to the total amount drank
        waterDrank += amount
        print(waterDrank)

        // Get the current progress in relation to the daily goal
        let currentProgress = waterDrank / dailyGoal
        // Set the new progress to the progressBar
        progressBar?.setProgress(currentProgress, animated: true)

        // Check if progress is below 0

        if (dailyGoal - waterDrank) <= 0.0 {
        // done
        }

        // Check if the daily goal has already been achieved
        if waterDrank >= Float(dailyGoal) {

            // Daily goal has been achieved - show message & abort code
            showAlert(title: "done", message: "!!")

            return

        }

    }

        // MARK: - Segue Action

    // Segue button to second view controller
    @IBAction func changeGoal(_ sender: Any) {

        performSegue(withIdentifier: "currentGoal", sender: self)

    }

    // Save variables
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        let secondViewController = segue.destination as! SecondViewController
        secondViewController.dailyGoal = self.dailyGoal

    }

    func updateViewController() {

        // Log new daily goal
        print(dailyGoal)

        // Print progressBar object
        print(waterDrank) // is 0, despite waterDrank having been increased in value before performing segue

        print(progressBar?.progress) // is nil, despite having not been nil before performing segue

    }



}

Second ViewController

    // Current goal label
    @IBOutlet weak var currentGoal: UILabel!

    // Goal picker
    @IBOutlet weak var goalPicker: UIPickerView!


    var dailyGoal = Float()

    let newDailyGoal = [Int()]

    // Initialize current progress
    var currentProgress = Float()

    // Water counter variable
    var waterDrank = Float(0)

    var percentageProgress = Float(0.0)

    override func viewDidLoad() {
        super.viewDidLoad()

    // setting secondViewController as delegate & data source for the UIPicker
    }

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {

        let vc = ViewController()
        let newDailyGoal = [1500, 1750, 2000, 2250, 2500]
        // Consider row

            switch row {

            case 0:
                self.dailyGoal = Float(newDailyGoal[0])
                vc.dailyGoal = self.dailyGoal

            case 1:
                self.dailyGoal = Float(newDailyGoal[1])
                vc.dailyGoal = self.dailyGoal

            case 2:
                self.dailyGoal = Float(newDailyGoal[2])
                vc.dailyGoal = self.dailyGoal

            case 3:
                self.dailyGoal = Float(newDailyGoal[3])
                vc.dailyGoal = self.dailyGoal

            case 4:
                self.dailyGoal = Float(newDailyGoal[4])
                vc.dailyGoal = self.dailyGoal

            default:

                print("daily goal is default: \(dailyGoal)")

            }


        // Export to ViewController.swift
        return "\(Int(dailyGoal)) ml"

    }

    // MARK: - Save button segue logic

    @IBAction func doneButton(_ sender: Any) {

        dismiss(animated: true, completion: nil)
        let firstViewController = ViewController()
        firstViewController.updateViewController()

    }

}

Your scenario requires you to pass the ViewController instance to the SecondViewController instead of creating a new one as you've done here. And then make a call for the function updateViewController in your done button action. So here's what you need to update.

In ViewController:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let secondViewController = segue.destination as! SecondViewController
    secondViewController.dailyGoal      = dailyGoal
    secondViewController.viewController = self
}

And in SecondViewController:

class SecondViewController: UIViewController {
    weak var viewController: ViewController?
...

    @IBAction func doneButton(_ sender: Any) {
        dismiss(animated: true)
        viewController?.updateViewController()
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM