使用Swift协议与泛型 [英] Using Swift protocols with generics
问题描述
我有一个简单的例子,它似乎应该工作:
import CoreData
@ objc协议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
}
}
所以我们有一个类 AbstractModel
符合协议 CoreDataModel
和 CoreDataModel
定义一个可选的类方法 entityName
。
但是,这一行:
var name = T.entityName?()
会导致错误:
预期的成员名称或类型名称后的构造函数调用
$ <$ p
$ b
编辑
删除 @optional
从声明和更改函数一点允许代码编译,但现在我得到一个运行时错误说,
'Swift动态转换失败'
@objc protocol CoreDataModel {
class func entityName () - > String
}
class AbstractModel:NSManagedObject,CoreDataModel {
class func entityName() - > String {
returnAbstractModel
}
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
}
}
我不能解释为什么你的代码导致运行时异常。但是如果你改变
的函数原型
class func create< T:CoreDataModel>(aClass:类型,上下文:NSManagedObjectContext) - > T
到
code> class func create< T:NSManagedObject其中T:CoreDataModel>(aClass:T.Type,context:NSManagedObjectContext) - >假设您的托管对象子类符合协议,例如 $extension事件:CoreDataModel {
class func entityName() - > String {
returnEvent
}
}
这将工作并创建一个新对象:
let newManagedObject = AbstractModel.create(Event.self,context:context)
或者,您可以使用从
Swift:return Array of type self 和
定义NSManagedObjectContext
类的扩展:扩展NSManagedObjectContext {
func create< T:NSManagedObject其中T:CoreDataModel>(entity:T.Type) - > T {
var classname = entity.entityName()
var object = NSEntityDescription.insertNewObjectForEntityForName(classname,inManagedObjectContext:self)as T
return object
}
}
然后将创建一个新对象
let newManagedObject = context.create(Event.self)
I have a simple example that seems like it should work:
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 } }
So we have a class called
AbstractModel
which conforms to the protocolCoreDataModel
, andCoreDataModel
defines an optional class method calledentityName
.However, this line:
var name = T.entityName?()
causes the error:
Expected member name or constructor call after type name
Any idea what I'm doing wrong?
Edit
Removing the word
@optional
from the declaration and changing the function a bit allows the code to compile, but now I get a runtime error saying that the'Swift dynamic cast failed'
@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 } }
解决方案I cannot explain why your code causes a runtime exception. But it works if you change the function prototype
class func create<T : CoreDataModel>(aClass:T.Type, context:NSManagedObjectContext) -> T
to
class func create<T : NSManagedObject where T: CoreDataModel>(aClass:T.Type, context:NSManagedObjectContext) -> T
Assuming that your managed object subclass conforms to the protocol, for example
extension Event : CoreDataModel { class func entityName() -> String { return "Event" } }
then this works and creates a new object:
let newManagedObject = AbstractModel.create(Event.self, context: context)
Alternatively, you could use the approach from the answer to "Swift: return Array of type self" and define an extension to the
NSManagedObjectContext
class: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 } }
Then a new object would be created as
let newManagedObject = context.create(Event.self)
这篇关于使用Swift协议与泛型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!