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

时间:2014-11-24 16:17:12

标签: swift core-data nsmanagedobject

在创建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)
    }

}

3 个答案:

答案 0 :(得分: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)
    }
}

然后

let obj = YourEntity.createInContext(context)

有效,编译器将obj的类型正确推断为YourEntity

答案 1 :(得分: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)
    }
}

Init方法的隐式返回类型为Self且没有强制转换 技巧是必要的。

let obj = YourEntity(context: context)

创建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)
    }
}

答案 2 :(得分:4)

在Swift 2中,有一个使用协议和协议扩展的非常智能的解决方案

protocol Fetchable
{
  typealias FetchableType: NSManagedObject

  static var entityName : String { get }
  static func createInContext(context: NSManagedObjectContext) ->  FetchableType
}

extension Fetchable where Self : NSManagedObject, FetchableType == Self
{
  static func createInContext(context: NSManagedObjectContext) -> FetchableType
  {
    return NSEntityDescription.insertNewObjectForEntityForName(entityName, inManagedObjectContext: context) as! FetchableType
  }
}

在每个NSManagedObject子类中添加协议Fetchable并实现属性entityName

现在函数MyEntity.createInContext(…)将返回正确的类型而无需进一步的类型转换。