core data - tutorial - Usando protocolos Swift con genéricos
swift 4 core data tutorial (2)
Tengo un ejemplo simple que parece que debería funcionar:
import CoreData
@objc protocol CoreDataModel {
@optional class func entityName() -> String
}
class AbstractModel: NSManagedObject, CoreDataModel {
class func create<T : CoreDataModel>(context:NSManagedObjectContext) -> T {
var name = T.entityName?()
var object = NSEntityDescription.insertNewObjectForEntityForName(name, inManagedObjectContext: context) as T
return object
}
}
Entonces, tenemos una clase llamada AbstractModel
que se ajusta al protocolo CoreDataModel
, y CoreDataModel
define un método de clase opcional llamado entityName
.
Sin embargo, esta línea:
var name = T.entityName?()
causa el error:
Nombre de miembro esperado o llamada de constructor después del nombre de tipo
¿Alguna idea de lo que estoy haciendo mal?
Editar
Eliminar la palabra @optional
de la declaración y cambiar la función un poco permite que el código se compile, pero ahora recibo un error de tiempo de ejecución que indica que el
''Falló el lanzamiento dinámico de Swift''
@objc protocol CoreDataModel {
class func entityName() -> String
}
class AbstractModel: NSManagedObject, CoreDataModel {
class func entityName() -> String {
return "AbstractModel"
}
class func create<T : CoreDataModel>(aClass:T.Type, context:NSManagedObjectContext) -> T {
var name = aClass.entityName()
var object = NSEntityDescription.insertNewObjectForEntityForName(name, inManagedObjectContext: context) as T
return object
}
}
De "El lenguaje de programación Swift"
Como T es un marcador de posición, Swift no busca un tipo real llamado T.
Como T no es un tipo real, tal vez no sea útil lanzarlo a T.
No puedo explicar por qué tu código causa una excepción de tiempo de ejecución. Pero funciona si cambias el prototipo de la función
class func create<T : CoreDataModel>(aClass:T.Type, context:NSManagedObjectContext) -> T
a
class func create<T : NSManagedObject where T: CoreDataModel>(aClass:T.Type, context:NSManagedObjectContext) -> T
Suponiendo que su subclase de objeto gestionado se ajusta al protocolo, por ejemplo
extension Event : CoreDataModel {
class func entityName() -> String {
return "Event"
}
}
entonces esto funciona y crea un nuevo objeto:
let newManagedObject = AbstractModel.create(Event.self, context: context)
Alternativamente, puede usar el enfoque de la respuesta a " Swift: return Array of type self " y definir una extensión a la clase NSManagedObjectContext
:
extension NSManagedObjectContext {
func create<T : NSManagedObject where T : CoreDataModel >(entity: T.Type) -> T {
var classname = entity.entityName()
var object = NSEntityDescription.insertNewObjectForEntityForName(classname, inManagedObjectContext: self) as T
return object
}
}
Entonces se crearía un nuevo objeto como
let newManagedObject = context.create(Event.self)