Search code examples
xcodecore-data

Core Data cannot assign value of type optional to type entity


In my code below the variable number is increased by 10 every time when button is pressed. I want to overwrite number to the old one then save, fetch and display it on the View. Unfortunately I get the following error message in func fetchStats() How can I assign a type of optional to a type entity? Or easier to say: How can I overwrite the existing variable "number" with the old one, then save, fetch it with Core Data (to entity (Statsohs) with attribute (value)) and finally display it?

import UIKit
import CoreData

class ViewController: UIViewController {

    var number : Double = 0
    
    //Reference to Managed Object Context
    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    
    //Data for the Stats
    var average : Statsohs?

    @IBOutlet weak var LabelStats: UILabel!
    //--------------------------------------------------------------------------------------
    override func viewDidLoad() {
        super.viewDidLoad()

        fetchStats()
        
    }
//--------------------------------------------------------------------------------------
    @IBAction func ActionButton(_ sender: UIButton) {

        number = number + 10
        
        average = Statsohs(context: context)
        average?.value = number
        LabelStats.text = String(format: "%.2f", average!.value)
        
        //Save the data
                do {
                    try context.save()
                            
                }
                    catch {
                            
                }
        
    }
//--------------------------------------------------------------------------------------
    func fetchStats() {
        
            //Fetch the data from CoreData to display in the View
            do {
                average = try context.fetch(Statsohs.fetchRequest())
                   //Cannot assign value of type '[Statsohs]' to type 'Statsohs'
            }
            catch {
                
            }
        }
    
}

I tried different declarations of average in the beginning, e.g.: average : [Statsohs]? But then I will get the same error message in Action at average = Statsohs(conext: context) And also member of type '[Statsohs]' has no member 'value'

I hope its possible in that way to assign value to Statsohs, save, fetch, display every time the updated value.


Solution

  • fetch returns always an array of records (multiple items) even if there is only one.

    To overwrite an attribute of a record you have to fetch the record, modify the attribute and save it back.

    In fetchStats fetch the (single) record which is the first in the array. Assign it to average and its value to number. If it doesn't exist create one and assign zero to value

    func fetchStats() {
            //Fetch the data from CoreData to display in the View
         do {
            if let found = try context.fetch(Statsohs.fetchRequest()).first {
                average = found
                number = found.value
            } else {    
                average = Statsohs(context: context)
                average?.value = 0
                saveData()
            }
            displayData()
                
        } catch {
            print(error)
        }
    }
    

    In actionButton increment number by 10, assign the result to value, display and save the data

    @IBAction func actionButton(_ sender: UIButton) {
        number += 10.0
        average?.value = number
        saveData()
        displayData()
    }
    

    Finally add the helper methods displayData and saveData

    func saveData() {
        do {
            try context.save()       
        } catch {
            print(error)              
        }
    
    }
    
    func displayData() {
        labelStats.text = String(format: "%.2f", number)
    }