如何在Swift中创建通用的便利初始化程序?

时间:2015-06-17 17:01:07

标签: swift generics

我正在使用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'。”

3 个答案:

答案 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}来调用已经采用了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)