Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error with Swift and Core Data: fatal error: use of unimplemented initializer 'init(entity:insertIntoManagedObjectContext:)'

I have the following class that inherits from NSManagedObject:

import Foundation
import CoreData


class Note: NSManagedObject {



    @NSManaged var text: String
    @NSManaged var name: String


     init(name: String, text:String, context: NSManagedObjectContext){

        let entity = NSEntityDescription.entityForName("Note", inManagedObjectContext: context);
        super.init(entity: entity!, insertIntoManagedObjectContext: context)

        self.text = text
        self.name = name;

    }
}

When I create instances of it, everything works fine, but when I make a search for these entities, I get a very odd error:

fatal error: use of unimplemented initializer 'init(entity:insertIntoManagedObjectContext:)'

This is the code that causes the error:

func coreDatePlayground(){

    var note = Note(name: "A new note", text: "blah", context: self.managedObjectContext!)

    println("\(note.name)  \(note.text)")

    var noote2 = Note(name: "Another note", text: "blah blah", context: self.managedObjectContext!)


    managedObjectContext?.save(nil)

    var fetch = NSFetchRequest(entityName: "Note")
    // This line causes the crash.
    var results = self.managedObjectContext?.executeFetchRequest(fetch, error: nil)
    if let objects = results{
        println(objects.count)
    }

}

I found out that changing the initialiser by making it a convenience one and calling on self instead of on super gets rid of the issue, but I have no idea why.

 convenience init(name: String, text:String, context: NSManagedObjectContext){

    let entity = NSEntityDescription.entityForName("Note", inManagedObjectContext: context);
    self.init(entity: entity!, insertIntoManagedObjectContext: context)

    self.text = text
    self.name = name;

}

The code above works, but I have no idea why. Anybody knows what's going on? Is it a bug or is my fault?

like image 872
cfischer Avatar asked Oct 05 '14 11:10

cfischer


2 Answers

This is documented behavior.

Swift subclasses do not inherit their superclass initializers by default

For example, following code does not even compile, because Child does not inherit init(id:String) automatically. This mechanism make sure name in Child class properly initialized.

class Parent {
    var id:String
    init(id:String) {
        self.id = id
    }
}

class Child:Parent {
    var name:String
    init(id:String, name:String) {
        self.name = name
        super.init(id: id)
    }
}

var child1 = Child(id:"child1")

If you define only convenience initializers in subclass, then it automatically inherits all of its superclass designated initializers as documented in "Automatic Initializer Inheritance" section

like image 58
rintaro Avatar answered Oct 12 '22 12:10

rintaro


You must implement the following in your NSManagedObject subclass (this is the Swift 3.0 version):

@objc
private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
    super.init(entity: entity, insertInto: context)
}

The answer is kind of answering it, but not really directly.

The reasoning for this is that Swift does not inherit their supercalls designated initializers by default AND it seems as CoreData by uses this initializer when doing fetches (insert a breakpoint in the method to see). So here we "bring up" the designated initializer for CoreData to use.

If you have NSManagedObject base classes, you must also implement this method in those.

Credits to JSQCoreDataKit for the idea.

like image 31
kgaidis Avatar answered Oct 12 '22 12:10

kgaidis