我正在使用Swift中的泛型。我有NSManagedObject
类的扩展,并希望创建初始化程序,该初始化程序仅适用于实现我定义的某些协议的类。现在我有类似下面的东西,但这不起作用,甚至没有编译。你能帮我把它搞定吗?
public extension NSManagedObject {
public convenience init<Self: Nameable>(context: NSManagedObjectContext) {
let entity = NSEntityDescription.entityForName(Self.entityName(), inManagedObjectContext: context)!
self.init(entity: entity, insertIntoManagedObjectContext: context)
}
}
public protocol Nameable {
static func entityName() -> String
}
Xcode说:“功能签名中没有使用通用参数'Self'。”
答案 0 :(得分:11)
正如亚特已经解释的那样,你无法定义一个初始化器 仅限于实现协议的类型。或者,你 可以定义一个全局函数:
public protocol Nameable {
static func entityName() -> String
}
func createInstance<T : NSManagedObject>(type : T.Type, context : NSManagedObjectContext) -> T where T: Nameable {
let entity = NSEntityDescription.entity(forEntityName: T.entityName(), in: context)!
return T(entity: entity, insertInto: context)
}
然后用作
let obj = createInstance(Entity.self, context)
如果您定义方法,可以避免使用其他类型参数 如
func createInstance<T : NSManagedObject>(context : NSManagedObjectContext) -> T where T: Nameable { ... }
并将其用作
let obj : Entity = createInstance(context)
或
let obj = createInstance(context) as Entity
现在从上下文中推断出类型。
答案 1 :(得分:2)
在我看来,你正在描述这样的事情:
class Thing {}
func makeANewThing<T:ThingMaker>(caller:T) -> Thing {
let t = Thing()
return t
}
protocol ThingMaker {
}
class Dog : ThingMaker {
}
class Cat { // not a ThingMaker
}
let t = makeANewThing(Dog()) // ok
let t2 = makeANewThing(Cat()) // illegal
在现实生活中,我假设makeANewThing
实际上做 1>},但重点是它只能通过传递{{1}来调用已经采用了ThingMaker。
这可能是您在Swift 1中可以做的最好的。如果您只想将方法注入到采用某种协议的类中,那么您想要的是协议扩展 - 但这仅在Swift 2中可用。< / p>
答案 2 :(得分:0)
好的,感谢您对此主题的评论。我意识到@matt评论说我不能做我想的,因为它甚至不可能。我想不创建子类来使其工作,而且我不能理解这个问题。
最后,我找到了另一种获取实体名称的方法。它有利有弊,但我现在决定使用它。然后我为NSManagedObject
创建了扩展程序以使其正常工作。
extension NSManagedObject {
class func entityName() -> String {
let fullClassName = NSStringFromClass(object_getClass(self))
let nameComponents = split(fullClassName) { $0 == "." }
return last(nameComponents)!
}
public convenience init(context: NSManagedObjectContext) {
let name = self.dynamicType.entityName()
let entity = NSEntityDescription.entityForName(name, inManagedObjectContext: context)!
self.init(entity: entity, insertIntoManagedObjectContext: context)
}
}
然后
obj = Obj(context: ctx)