Swift访问隐式解包变量遇nil错误:CoreData目标保存异常
CoreData保存时goalType.rawValue为nil的问题
我跟着一份多年前的CoreData教程开发目标保存APP,完全按步骤操作,但保存功能出现nil错误。具体情况:在CreateGoalViewController中初始化FinishGoalViewController的goalType后,打印值是正确的,但进入FinishGoalViewController执行save函数时,goalType.rawValue变成nil,导致CoreData保存失败。
CreateGoalViewController代码
import UIKit class CreateGoalViewController: UIViewController, UITextViewDelegate { @IBOutlet weak var goalTextView: UITextView! @IBOutlet weak var shortTermButton: UIButton! @IBOutlet weak var longTermButton: UIButton! @IBOutlet weak var nextButton: UIButton! var userGoalType: GoalType = .shortTerm override func viewDidLoad() { super.viewDidLoad() nextButton.bindToKeyboard() shortTermButton.setSelectedColor() longTermButton.setDeselectedColor() print("\(userGoalType)") goalTextView.delegate = self } @IBAction func nextButtonPressed(_ sender: Any) { if goalTextView.text != "" && goalTextView.text != "What is your goal?" { guard let finishVC = storyboard?.instantiateViewController(withIdentifier: "FinishVC") as? FinishGoalViewController else {return} finishVC.initData(description: goalTextView.text!, type: userGoalType) print("\(finishVC.goalType.rawValue) after next button pressed") performSegue(withIdentifier: "goToFinish", sender: self) } } @IBAction func longTermButtonPressed(_ sender: Any) { userGoalType = .longTerm longTermButton.setSelectedColor() shortTermButton.setDeselectedColor() print("\(userGoalType)") } @IBAction func shortTermButtonPressed(_ sender: Any) { userGoalType = .shortTerm shortTermButton.setSelectedColor() longTermButton.setDeselectedColor() print("\(userGoalType)") } @IBAction func backButtonPressed(_ sender: Any) { dismiss(animated: true) } func textViewDidBeginEditing(_ textView: UITextView) { goalTextView.text = "" goalTextView.textColor = UIColor(ciColor: .black) } }
FinishGoalViewController代码
import UIKit import CoreData class FinishGoalViewController: UIViewController, UITextFieldDelegate { @IBOutlet weak var createButton: UIButton! @IBOutlet weak var pointsTextField: UITextField! var goalDescription: String! var goalType: GoalType! func initData(description: String, type: GoalType) { self.goalDescription = description self.goalType = type } override func viewDidLoad() { super.viewDidLoad() createButton.bindToKeyboard() pointsTextField.delegate = self } @IBAction func createGoalPressed(_ sender: Any) { if pointsTextField.text != ""{ self.save { finished in if finished { dismiss(animated: true) } } } } @IBAction func backButtonPressed(_ sender: Any) { dismiss(animated: true) } func save(completion: (_ finished: Bool) -> ()) { guard let managedContext = appDelegate?.persistentContainer.viewContext else {return} let goal = Goal(context: managedContext) goal.goalDescription = goalDescription goal.goalType = goalType.rawValue goal.goalCompletionValue = Int32(pointsTextField.text!)! goal.goalProgress = Int32(0) do{ try managedContext.save() print("successfully saved data") completion(true) }catch{ debugPrint("Could not save: \(error.localizedDescription)") completion(false) } } }
GoalType枚举代码
import Foundation enum GoalType: String { case longTerm = "Long Term" case shortTerm = "Short Term" }
问题原因
你在nextButtonPressed里手动实例化了FinishGoalViewController并调用initData,但随后用performSegue跳转时,系统会重新创建一个新的FinishGoalViewController实例,而不是你之前初始化的那个。所以真正跳转过去的VC里的goalType和goalDescription都是nil,自然会导致保存失败。
修复方法
方法1:用prepare(for:sender:)传递数据
删除手动实例化VC的代码,改用Segue的准备方法传递数据:
@IBAction func nextButtonPressed(_ sender: Any) { if goalTextView.text != "" && goalTextView.text != "What is your goal?" { performSegue(withIdentifier: "goToFinish", sender: self) } } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "goToFinish" { guard let finishVC = segue.destination as? FinishGoalViewController else { return } finishVC.initData(description: goalTextView.text!, type: userGoalType) } }
方法2:直接跳转到手动实例化的VC(不用Segue)
如果不想用Segue的准备方法,直接present手动创建的VC:
@IBAction func nextButtonPressed(_ sender: Any) { if goalTextView.text != "" && goalTextView.text != "What is your goal?" { guard let finishVC = storyboard?.instantiateViewController(withIdentifier: "FinishVC") as? FinishGoalViewController else {return} finishVC.initData(description: goalTextView.text!, type: userGoalType) print("\(finishVC.goalType.rawValue) after next button pressed") // 替换performSegue为present present(finishVC, animated: true) } }
内容的提问来源于stack exchange,提问作者BenG94
相关产品推荐
相关产品推荐

