0

I'm following a tutorial on CoreData and I've been following it exactly, yet when they run the app, everything works and saves correctly, yet I get a nil error. The tutorial is a few years old, so I'm not sure if something has been udpated in the way CoreData works. It's an app to save goals.

Here's the first view controller where you enter the text of the goal and if it is short or long term:

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)
    }
}

And here's the following view controller where you set the number of times you want to do that goal where the CoreData functions are:

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)
        }
    }
}

I'm getting a nil error in the save function with the goalType.rawValue turning up nil. The goal type is set up in an enum file:

import Foundation

enum GoalType: String {
    case longTerm = "Long Term"
    case shortTerm = "Short Term"
}

I'm not sure why there's an error. Because in the CreateGoalViewController, I print the goalType.rawValue from the following view controller and it comes up with the correct string, either short or long-term. But when FinishGoalViewController loads, it is all of a sudden nil.

burnsi
  • 6,194
  • 13
  • 17
  • 27
BenG94
  • 23
  • 5

1 Answers1

0

You are initiating and configuring your FinishGoalViewController in nextButtonPressed but you never use it. performSegue(withIdentifier: "goToFinish", sender: self) will create and push a new instance of FinishGoalViewController.

The most simple aproach would be to push your allready configured controller from your curent Controller. Remove performSegue(... and use.

self.navigationController?.pushViewController(finishVC, animated: true)

If you still want to use the segue, remove everything from the nextButtonPressed function, leaving just the performSegue(... line. After that add this function to your CreateGoalViewController controller.

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "goToFinish" {
        if let finishVC = segue.destination as? FinishGoalViewController {
            // configure finshVC here
        }
    }
}
burnsi
  • 6,194
  • 13
  • 17
  • 27