如何在NSManagedObject Swift扩展中创建托管对象子类的实例?

aml*_*szk 18 core-data nsmanagedobject swift

当创建一个扩展助手来NSManagedObject创建一个新的托管对象子类时,swift提供了Self模仿的类型,instancetype这很好,但我似乎无法进行类型转换AnyObject.下面的代码没有编译错误'AnyObject'不能转换为'Self'

救命?

extension NSManagedObject
{
    class func createInContext(context:NSManagedObjectContext) -> Self {
        var classname = className()
        var object: AnyObject = NSEntityDescription.insertNewObjectForEntityForName(classname, inManagedObjectContext: context)
        return object
    }


    class func className() -> String {
        let classString = NSStringFromClass(self)
        //Remove Swift module name
        let range = classString.rangeOfString(".", options: NSStringCompareOptions.CaseInsensitiveSearch, range: Range<String.Index>(start:classString.startIndex, end: classString.endIndex), locale: nil)
        return classString.substringFromIndex(range!.endIndex)
    }

}
Run Code Online (Sandbox Code Playgroud)

Mar*_*n R 26

(现在更新为Swift 3/4.可以在编辑历史中找到早期Swift版本的解决方案.)

您可以使用unsafeDowncast到的返回值转换NSEntityDescription.insertNewObject()Self (这是该方法实际上是所谓的类型):

extension NSManagedObject {
    class func create(in context: NSManagedObjectContext) -> Self {
        let classname = entityName()
        let object = NSEntityDescription.insertNewObject(forEntityName: classname, into: context)
        return unsafeDowncast(object, to: self)
    }

    // Returns the unqualified class name, i.e. the last component.
    // Can be overridden in a subclass.
    class func entityName() -> String {
        return String(describing: self)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后

let obj = YourEntity.createInContext(context)
Run Code Online (Sandbox Code Playgroud)

工作和编译器推断obj正确的类型YourEntity.

  • @MartinR 很好的解释。但我不明白为什么 func createInContext&lt;T&gt;(context:NSManagedObjectContext, type : T.Type) -&gt; T 需要 'type' 参数?不能通过调用函数的返回类型推断出“T”的类型吗?#newToSwift :) (2认同)

Mar*_*n R 9

这是通过实现初始化方法(使用Xcode 7.1测试)来解决问题的不同方法:

extension NSManagedObject {

    // Returns the unqualified class name, i.e. the last component.
    // Can be overridden in a subclass.
    class func entityName() -> String {
        return String(self)
    }

    convenience init(context: NSManagedObjectContext) {
        let eName = self.dynamicType.entityName()
        let entity = NSEntityDescription.entityForName(eName, inManagedObjectContext: context)!
        self.init(entity: entity, insertIntoManagedObjectContext: context)
    }
}
Run Code Online (Sandbox Code Playgroud)

Init方法具有隐式返回类型,Self并且不需要强制转换技巧.

let obj = YourEntity(context: context)
Run Code Online (Sandbox Code Playgroud)

创建该YourEntity类型的对象.


Swift 3/4更新:

extension NSManagedObject {

    // Returns the unqualified class name, i.e. the last component.
    // Can be overridden in a subclass.
    class func entityName() -> String {
        return String(describing: self)
    }

    convenience init(context: NSManagedObjectContext) {
        let eName = type(of: self).entityName()
        let entity = NSEntityDescription.entity(forEntityName: eName, in: context)!
        self.init(entity: entity, insertInto: context)
    }
}
Run Code Online (Sandbox Code Playgroud)