如何在Swift中为NSManagedObject子类创建指定的初始化器?

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
}

我想要创建一个方法,让我可以通过调用它来初始化新对象:

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

但是我收到了错误提示:

Convenience initializer for Alternative must delegate with self.init

我需要更改我的初始化程序以使我的示例使用起作用,应该做什么更改?

4个回答

44

方便的初始化方法必须在self上调用指定的初始化方法:

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

将会被称为

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

另外,你还可以将实体描述的创建移至方便的初始化程序中,而不是将其作为参数传递(如Mundi的答案所激发的那样):

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:我正在尝试将这些放入NSManagedObject的扩展中。您认为这应该是可能的吗?因为我得到了一个编译错误。它似乎正在寻找来自NSManagedObject.h的NS_DESIGNATED_INITIALIZER来使用。有什么想法吗? - Damien
@Damien:没有看到实际的代码和精确的错误信息,我无法回答。 - Martin R
1
@Damien:在NSManagedObject扩展中创建“Person”实体是没有意义的。请参考http://stackoverflow.com/questions/24834753/using-swift-protocols-with-generics/24839064#24839064了解另一种(通用)方法。 - Martin R
哎呀!你说得对!在“人员”级别上工作得很好,我只是将它推到了一个扩展中。我应该再考虑一下的。谢谢你的提示! - Damien

10

我只是用一个类函数完成了这个操作:

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
}
你可以像这样调用它(几乎一样漂亮):
let item = Item.newInstance(text, notes:notes, context:context)

所以不能使用 Alternative("third platform", True, entityDescription, managedObjectContext) 来制作指定的初始化程序吗? 我的意见是,使用 Alternative.newInstance(...) 看起来不太好看。 - bogen
2
+1 是指在初始化器中不需要传递实体描述。 - Martin R
你可以根据自己的喜好给它取另一个名字,而不是 newInstance()。此外,你仍然需要命名参数,而不仅仅是参数列表,否则你的代码可读性会降低。总之,类方法的解决方案并不比其他初始化程序更长或更不美观。 - Mundi
在这个例子中,当您调用函数时,您没有设置上下文吗? - FredFlinstone
你在哪里设置上下文,如何设置? - rcat24
@rcat24 通常情况下,您可以从控制器/后台服务等上下文中获取上下文。这就是为什么此函数将上下文作为参数的原因。 - Mundi

4

Swift 3.1 解决方案:

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
}

2
你需要从你的便利初始化程序中调用指定的初始化程序。 此外,您不应该从任何初始化程序中返回任何内容。
为了遵守苹果的Swift文档中描述的规则,您首先需要为您的子类提供一个指定的初始化程序,该初始化程序调用其超类的init(),然后您可以提供一个方便的初始化程序,该程序仅允许从其类声明中调用指定的初始化程序。
这将起作用:(已更新:考虑到使用@NSManaged标记的核心数据属性由运行时自动初始化。感谢@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)
}

1
核心数据属性(标记为@NSManaged)由运行时自动初始化。 - Martin R
这将会引起问题。请参考此问题:https://dev59.com/UF8e5IYBdhLWcg3wAWcL - rintaro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接