Search code examples
ioscore-datansfetchrequestswift2

Core Data - NSManagedObject returning nil


I wrote two seperate functions fetchRecords and displayRecords written in Appdelegate Class. fetchRecords function will fetch all records from the entity and it is working fine.displayRecords function accepts the return value from fetchRecords function and prints all the records one by one.

I have one view controller which calls these two functions to do the desired task. My problem is result.count in displayRecords shows the total number of records available in fetched records.While printing the records one by one the value is nil.

override func viewDidLoad() {
super.viewDidLoad()
    let fetchedRecords = AppDelegate().fetchRecords(fromEntity: "Dashboard")
    AppDelegate().displayRecords(fromFetchedRecords: fetchedRecords)   
}

And here is the fetchRecords and displayRecords functions written in AppDelegate Class

  func fetchRecords(fromEntity entity:String) -> Array<AnyObject> {
    var fetchedResult:Array<AnyObject> = []
    let fetchRequest = NSFetchRequest()
    let entityDescription = NSEntityDescription.entityForName(entity, inManagedObjectContext: self.managedObjectContext)!
    fetchRequest.entity = entityDescription
    do{
        fetchedResult = try self.managedObjectContext.executeFetchRequest(fetchRequest)              
    }catch{
        let fetchError = error as NSError?
        print(fetchError!)
    }
   return fetchedResult
}

func displayRecords(fromFetchedRecords result:Array<AnyObject>) {
    print("Total records:\(result.count)")
    if (result.count > 0) {
        for data in result {
        let dashboard = data as! NSManagedObject
        print("Value: \(dashboard.valueForKey("count"))")
        }
    }
}

Adding my data model here enter image description here

I will share the data insertion code also.

func saveDashBoardData(dictionary: Dictionary<String, String>) {
    print(NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask))

    //Create Manage Object
    let entityDescription: NSEntityDescription = NSEntityDescription.entityForName("Dashboard", inManagedObjectContext: self.managedObjectContext)!
    for data in dictionary {
        let dashboardObject = Dashboard(entity: entityDescription,insertIntoManagedObjectContext: self.managedObjectContext)
        dashboardObject.type  = data.0
        dashboardObject.count = data.1
        do {
            try self.managedObjectContext.save()
            print("Data saved succesfully")
        }
        catch {
            print(error)
        }
    }
}

Solution

  • The issue is that AppDelegate() creates always a new instance of the class which is not the same as the "hard-coded" delegate instance of the application.

    You have to write

    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let fetchedRecords = appDelegate.fetchRecords(fromEntity: "Dashboard")
    appDelegate.displayRecords(fromFetchedRecords: fetchedRecords)
    

    Since you have created a custom subclass of NSManagedObject use it as type rather than NSManagedObject or – worse – the unspecified AnyObject. It makes many things much easier:

    func fetchRecords(fromEntity entity:String) -> [Dashboard] {
      let fetchRequest = NSFetchRequest()
      let entityDescription = NSEntityDescription.entityForName(entity, inManagedObjectContext: self.managedObjectContext)!
      fetchRequest.entity = entityDescription
      do {
         return try self.managedObjectContext.executeFetchRequest(fetchRequest) as! [Dashboard]              
      } catch let fetchError as NSError {
         print(fetchError!)
      }
      return [Dashboard]()
    }
    
    func displayRecords(fromFetchedRecords result:[Dashboard]) {
        print("Total records:\(result.count)")
    
        for dashboard in result { // the check for empty is not needed
           print("Value: \(dashboard.count)")
        }
    }