How to make a designated initializer for NSManagedObject subclass in Swift?
Solution 1
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
}
Solution 2
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)
Solution 3
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
}
Solution 4
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)
}
Comments
-
bogen about 4 years
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?
-
bogen over 9 yearsSo 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(...) -
Martin R over 9 years+1 for not needing to pass an entity description into the initializer.
-
Martin R over 9 yearsCore data properties (marked with
@NSManaged
) are initialized automatically by the runtime. -
rintaro over 9 yearsThis will cause a problem. see this question: stackoverflow.com/questions/26202346/…
-
Mundi over 9 yearsYou 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. -
Damien over 9 yearsQuick 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?
-
Martin R over 9 years@Damien: Not without seeing the actual code and the exact error message.
-
Martin R over 9 years@Damien: It does not make sense to create a "Person" entity in a NSManagedObject extension. See stackoverflow.com/questions/24834753/… for an alternative (generic) approach.
-
Damien over 9 yearsDoh! 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!
-
FredFlinstone about 6 yearsWhen you call your func in the example you do not set the context?
-
rcat24 about 6 yearswhere do you set the context, and how?
-
Mundi about 6 years@rcat24 Typically you have the context from your controller / background service etc. That's why this function has the context as an argument.