You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 10:26:04