ios - 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()
}
}
推荐阅读
- uml - 系统序列图是分析还是设计的一部分?
- google-apps-script - 将多个 Google 表格合并为一个具有多个标签的表格
- c - 如何控制数组的长度
- entity-framework - 使用实体框架查询格式化日期时间未使用 ToString("MM/dd/yyyy") 正确排序
- python - 连接 numpy 数组和 keras 层
- javascript - 推送数组中的值以匹配特定格式
- python - 将数据框列表附加到python中的数据框列表
- excel - 将所有列值与 Excel 中的单个单元格进行比较
- r - R中的简单绘图
- python - Python pytz:显示时区的实际时间