-1

So I'm new to core data, starting doing some tutorials and got a very basic setup where a 10 scores are saved from the AppDelegate and that works fine (am able to fetch and print from the console).

Then when I want to use a fetchrequest in another VC to retrieve the data which has been saved successfully, I get the following error: fatal error: unexpectedly found nil while unwrapping an Optional value. Here's the code to retrieve the data:

import Foundation
import CoreData
import UIKit


class testVC: UIViewController {
var managedObjectContext: NSManagedObjectContext!
var scores = [Scores]()

@IBOutlet weak var retrieveDataLabel: UIButton!
@IBOutlet weak var saveLabel: UIButton!
  override func viewDidLoad() {
    super.viewDidLoad()

     }


@IBAction func retrieveData(sender: AnyObject) {
    let fetchRequest = NSFetchRequest(entityName: "Scores")
    do {
        if let results = try managedObjectContext.executeFetchRequest(fetchRequest) as? [Scores]{
            scores = results
            for result in results {
                if let gameScore = result.valueForKey("gameScore") as? Int{
                    print("Your score is \(gameScore)")
                }
            }
        }
    }catch{
        print("Error fetching data")
    }}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

}

Since I'm using if let .. shouldn't I be getting "Error fetching data"? instead of getting the fatal error? How come I can retrieve the data when loading the app but not when I try to retrieve the data in a different VC using the same code?

I've looked at other questions relating to fatal error found nil while unwrapping an optional value: What does "fatal error: unexpectedly found nil while unwrapping an Optional value" mean?

fatal error: unexpectedly found nil while unwrapping an Optional value and it seems that I'm basically trying to retrieve something which isn't there, but the data is saved indeed and I can retrieve it in the console when starting the app. Using the same fetch request I'd expect to get identical results when I load the app and retrieve the data but that's not the case.

What am I missing here? It feels like it should be very basic but for some reason just cannot get it to work after trying for 2 days.

app delegate code to save and retrieve data:

 func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    // Override point for customization after application launch.
    //addTestData()
    let fetchRequest = NSFetchRequest(entityName: "Scores")
    do {
        if let results = try managedObjectContext.executeFetchRequest(fetchRequest) as? [NSManagedObject]{
            for result in results {
                if let gameScore = result.valueForKey("gameScore") as? Int{
                    print("Your score is  \(gameScore)")
                }
            }
        }
    }catch{
        print("Error fetching data")
    }

    return true
}
func addTestData(){

    guard let entity = NSEntityDescription.entityForName("Scores", inManagedObjectContext: managedObjectContext) else{
        fatalError("Could not find entity description")
    }
    for i in 1...10{
        let score = Scores(entity: entity, insertIntoManagedObjectContext: managedObjectContext)
        score.gameScore = i
    }
    do {
        try managedObjectContext.save()
    } catch {
        // Replace this implementation with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        let nserror = error as NSError
        NSLog("Unresolved error \(nserror), \(nserror.userInfo)")
        abort()
    }

}

Any help would be greatly appreciated!

Community
  • 1
  • 1
ThirtyKnots
  • 63
  • 1
  • 1
  • 6

3 Answers3

1

When you use if let, you are checking to see if it is possible to make the result as an Int. You want to see if that result exists first. Try this:

for result in results {
            if let gameScore = result.valueForKey("gameScore") {
                print("Your score is \(gameScore as! Int)")
            }
        }
Pranav Wadhwa
  • 7,666
  • 6
  • 39
  • 61
  • The following returns the error: if let results... so it crashes before it reaches the result from the fetch but with this error: fatal error: unexpectedly found nil while unwrapping an Optional value and not the following: print("Error fetching data") – ThirtyKnots May 22 '16 at 15:14
  • Try taking out the do and catch. You don't need it. It might help if you remove it – Pranav Wadhwa May 22 '16 at 15:56
0

So I did manage to get it working, using the following for managedObjectContext: let managedContext = AppDelegate().managedObjectContext

I'm still puzzled why I didn't get the error which was specified in the catch but at least it's working now.

Thanks for your answers!

ThirtyKnots
  • 63
  • 1
  • 1
  • 6
0

The issue is the nil NSManagedObjectContext (declared but no value)

By definition executeFetchRequest returns a non-optional array on success and since you are supposed to know from the Core Data model that the entity Scores returns always Scores objects you can safely write

do {
    scores = try managedObjectContext.executeFetchRequest(fetchRequest) as! [Scores]

And obviously using a NSManagedObject subclass use the property directly to avoid the type casting. You need the optional binding only if the property gameScore is declared as optional.

    for result in results {
        if let gameScore = result.gameScore {
            print("Your score is \(gameScore)")
        }

However for a Int value like a score a non-optional is more reasonable, than you can reduce the code to

    for result in results {
       print("Your score is \(result.gameScore)")
    }
vadian
  • 274,689
  • 30
  • 353
  • 361