Подтвердить что ты не робот

Как создать экземпляры подклассов управляемого объекта в расширении NSManagedObject Swift?

При создании вспомогательного помощника расширения для NSManagedObject для создания нового подкласса управляемого объекта, swift предоставляет тип Self для mimic instancetype, который является большим, но я не могу показаться typecast из 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)
    }

}
4b9b3361

Ответ 1

(Обновлено для 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.

Ответ 2

Вот другой подход к решению проблемы, реализующий метод инициализатора (протестированный с 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.


Свифт 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)
    }
}

Ответ 3

В 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(…) вернет правильный тип без последующего литья типов.