35
class Alternative: NSManagedObject {

    @NSManaged var text: String
    @NSManaged var isCorrect: Bool
    @NSManaged var image: NSData
} 

convenience init(text: String, isCorrect: Bool, entity: NSEntityDescription, insertIntoManagedObjectContext context: NSManagedObjectContext!) {
        let alternative = Alternative(entity: entity, insertIntoManagedObjectContext: context) as Alternative
        alternative.text = text
        alternative.isCorrect = isCorrect
        return alternative
}

I want to make a method that lets me initialize new objects with this call:

let newAlternative = Alternative("third platform", True, entityDescription, managedObjectContext)

But i get the error:

Convenience initializer for Alternative must delegate with self.init

What do i need to change in my initalizer to make my example usage work?

Cœur
  • 37,241
  • 25
  • 195
  • 267
bogen
  • 9,954
  • 9
  • 50
  • 89

4 Answers4

44

A convenience initializer must call the designated initializer on self:

convenience init(text: String, isCorrect: Bool, entity: NSEntityDescription, insertIntoManagedObjectContext context: NSManagedObjectContext!) {
    self.init(entity: entity, insertIntoManagedObjectContext: context)
    self.text = text
    self.isCorrect = isCorrect
}

which would be called as

let newAlternative = Alternative(text: "third platform", isCorrect: true,
     entity: entityDescription, insertIntoManagedObjectContext: managedObjectContext)

In addition, you could also move the creation of the entity description into the convenience initializer instead of passing it as an argument (as motivated by Mundi's answer):

convenience init(text: String, isCorrect: Bool, insertIntoManagedObjectContext context: NSManagedObjectContext!) {
    let entity = NSEntityDescription.entityForName("Alternative", inManagedObjectContext: context)!
    self.init(entity: entity, insertIntoManagedObjectContext: context)
    self.text = text
    self.isCorrect = isCorrect
}
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Quick additional question @martin-r: I am trying to place these into an extension onto NSManagedObject. Do you think this should this be possible, as I'm getting a compile error. It seems to be looking for the NS_DESIGNATED_INITIALIZER from NSManagedObject.h to be used. Any thoughts? – Damien Oct 18 '14 at 18:30
  • @Damien: Not without seeing the actual code and the exact error message. – Martin R Oct 18 '14 at 19:04
  • 1
    @Damien: It does not make sense to create a "Person" entity in a NSManagedObject extension. See http://stackoverflow.com/questions/24834753/using-swift-protocols-with-generics/24839064#24839064 for an alternative (generic) approach. – Martin R Oct 18 '14 at 19:18
  • Doh! You're right! Was working ok up at the "Person" level and I just pushed it down to an extension. I should have thought about it a bit more. Thanks for the hint! – Damien Oct 18 '14 at 19:21
10

I simply did this with a class function:

class func newInstance(text: String, notes:String, 
                    context: NSManagedObjectContext) -> Item {
    var item = NSEntityDescription.insertNewObjectForEntityForName("Item", 
               inManagedObjectContext: context) as Item
    item.notes = notes
    item.text = text
    return item
}

which you can call like this (almost as pretty):

let item = Item.newInstance(text, notes:notes, context:context)
Mundi
  • 79,884
  • 17
  • 117
  • 140
  • So its not possible to make a designated initializer with `Alternative("third platform", True, entityDescription, managedObjectContext)` ? My opinion is that it doesnt look as good with Alternative.newInstance(...) – bogen Oct 17 '14 at 15:48
  • 2
    +1 for *not* needing to pass an entity description into the initializer. – Martin R Oct 17 '14 at 15:53
  • You can give it another name to your liking instead of `newInstance()`. Also, you still want named parameters, not just a parameter list, otherwise your code will be less readable. - In summary the class method solution is not really longer or less aesthetic than other initializers. – Mundi Oct 18 '14 at 08:13
  • When you call your func in the example you do not set the context? – FredFlinstone Apr 10 '18 at 09:17
  • where do you set the context, and how? – rcat24 Apr 28 '18 at 17:30
  • @rcat24 Typically you have the context from your controller / background service etc. That's why this function has the context as an argument. – Mundi Apr 28 '18 at 21:27
4

Swift 3.1 solution:

convenience init(text: String, isCorrect: Bool, image: NSData, moc: NSManagedObjectContext) {
        let entity = NSEntityDescription.entity(forEntityName: "Alternative", in: moc)
        self.init(entity: entity!, insertInto: moc)
        // vars
        self.text = text
        self.isCorrect = isCorrect
        self.image = image
}
Alessandro Ornano
  • 34,887
  • 11
  • 106
  • 133
2

You have to call a designated initializer from your convenience initializer. Also, you do not return anything from any initializer.

To fulfill the rules, which are described in Apple's Swift documentation you first need a designated initializer for your subclass, which calls the init() of its superclass, then you can offer a convenience initializer which is only allowed to call a designated initializer from its class declaration.

This would work: (Updated: Taken into account that core data properties marked with @NSManaged are initialized automatically by the runtime. Thanks @Martin R)

init(text: String, isCorrect: Bool, image: NSData, entity: NSEntityDescription,   insertIntoManagedObjectContext context: NSManagedObjectContext!) {
    super.init(entity: entity, insertIntoManagedObjectContext: context)
}

convenience init(text: String, isCorrect: Bool, entity: NSEntityDescription, insertIntoManagedObjectContext context: NSManagedObjectContext!) {
    self.init(text: text, isCorrect: isCorrect, entity: entity, insertIntoManagedObjectContext: context)
}
marcusficner
  • 915
  • 8
  • 13
  • 1
    Core data properties (marked with `@NSManaged`) are initialized automatically by the runtime. – Martin R Oct 17 '14 at 15:57
  • This will cause a problem. see this question: http://stackoverflow.com/questions/26202346/error-with-swift-and-core-data-fatal-error-use-of-unimplemented-initializer-i – rintaro Oct 17 '14 at 17:08