1

I am using Core Data in Swift and am having trouble storing the array returned from a fetch request. I have two entities in my data model: Task and Homework. Homework's parent entity is Task. I auto generated the classes for the two entities:

Task.swift

import Foundation
import CoreData

class Task: NSManagedObject {

    @NSManaged var name: String
    @NSManaged var due: NSDate
    @NSManaged var subject: Subject

}

Homework.swift

import Foundation
import CoreData

class Homework: Task {
}

In my view controller, in view did load, I have the following code.

var error: NSError? = nil
let fetchRequest = NSFetchRequest()
let entity = NSEntityDescription.entityForName("Task", inManagedObjectContext: managedObjectContext)
fetchRequest.entity = entity
tasks = managedObjectContext.executeFetchRequest(fetchRequest, error: &error) as [Task]

Earlier in the view controller, I initialized tasks:

var tasks : [Task] = []

However, when I run the the application, I get the following runtime error at the line where I assign the array to tasks: fatal error: array cannot be downcast to array of derived

If I replace the assignment line with var temp = managedObjectContext.executeFetchRequest(fetchRequest, error: &error) as [NSManagedObject], the error does not occur, but I need to save it as an array of Tasks in order to be able to use the custom classes that I generated. What am I doing wrong?

golddove
  • 1,123
  • 2
  • 14
  • 30
  • Compare "Implementing Core Data Managed Object Subclasses" in https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/BuildingCocoaApps/WritingSwiftClassesWithObjective-CBehavior.html. – Martin R Jul 24 '14 at 07:24

2 Answers2

2

You have to add the module or app name to the class name in the model editor:

MyApp.Task

This has to be done after you generate the class file, otherwise that part fails. I consider this a bug in the current beta, and have raised it as such.

My previous answer stated to use the @objc decorator, which also works, but the above solution is documented in the swift / cocoa reference.

jrturton
  • 113,418
  • 30
  • 247
  • 261
  • 1
    According to https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/BuildingCocoaApps/WritingSwiftClassesWithObjective-CBehavior.html, the proper solution is to include the module/app name in the entities class (and then it works without `@objc(Task)`, at least in my test). Of course Xcode should to that when auto-creating the managed object subclasses. – Martin R Jul 24 '14 at 07:21
  • @MartinR oh, interesting. Is that new in the documentation or have I just been missing it all this time? Would be nice for it to point to it from the NSManagedObject class reference... – jrturton Jul 24 '14 at 07:55
  • I don't know, but Ben's answer to the duplicate question is from June 11, so I *assume* that it is already documented for a while. – Martin R Jul 24 '14 at 08:09
  • OK thanks. I've updated my bug report to be a documentation fix and for the module name to be added to the class by the generator. – jrturton Jul 24 '14 at 08:14
1

According to the XCode Release Notes for Beta 4 the downcast should work now:

Objects of a class type, such as NSObject or NSArray, can now be downcast to bridged Swift types.

(Haven't tried that though)

However, you can cast the objects in your tasks array when you need them:

tasks = managedObjectContext.executeFetchRequest(fetchRequest, error: &error)  // array of NSManagedObjects

for obj in tasks {
    let task = obj as Task
    ...
}
zisoft
  • 21,200
  • 10
  • 56
  • 72