强制模板成为协议

时间:2017-07-11 10:42:55

标签: ios swift generics protocols

如何确保给定模板参数是协议?

GKEntity有一个名为component(ofType: class)的函数,我想添加component(ofProtocol: Protocol)。它看起来像这样:

extension GKEntity {
    func component<T: Protocol>(ofProtocol: T) -> T? {
        return self.components.first() { component in
            return component.conforms(to: ofProtocol)
        } as? T
    }
}

我想在一个包含对实体的引用的组件中使用它,如下所示:

let component = self.entity?.component(ofProtocol: SpriteComponentProtocol)

但不知怎的,我总是得到:

显示所有消息

Cannot convert value of type 'SpriteComponentProtocol.Protocol' to expected argument type 'Protocol'

更新

我的想法是我有一个Sprite组件:

protocol SpriteComponentProtocol {
    var spriteNode: SKSpriteNode { get set }
}

class SpriteComponent: GKComponent {
    var spriteNode: SKSpriteNode?
}

控件的另一个组件:

protocol PlayerControlComponentProtocol {
    var steerAngle: Double { get set }
}

class PlayerControlComponent: GKComponent, PlayerControlComponentProtocol {
    var steerAngle: Double = 90.0

    override func update(deltaTime seconds: TimeInterval) {
        //here i do manipulate the spriteComponent.spriteNode
        let comp = self.entity?.component(ofProtocol: SpriteComponentProtocol)
    }
}

我希望能够随时更换SpriteComponent。

1 个答案:

答案 0 :(得分:1)

您的代码存在的问题是Protocol是一种描述Obj-C协议的opaque类型,因此如果您要将SpriteComponentProtocol.self桥接到它,则需要标记{{1} } SpriteComponentProtocol(但即使你这样做了;你也不能转发到@objc,因为返回的实例不是T类型的。)< / p>

但话虽如此,您不需要在此处使用Obj-C Protocol类型或Protocol方法,您只需使用条件类型转换运算符{{1}在conforms(to:) 的重载中没有 as?上的component(ofType:)约束:

GKComponent

我们在这里使用T是为了避免评估所有extension GKEntity { func component<T>(ofType type: T.Type) -> T? { return self.components.lazy.flatMap{ $0 as? T }.first } } ,然后评估lazycomponents以获得第一个元素&# 39; s可转换为flatMap(_:)(并且在first为协议类型的情况下,这为我们提供了符合协议的第一个元素。)

然后您可以像这样简单地使用它:

T

在Swift 4中,您可以完全删除此重载,而只需使用类存活元数据类型调用T&n; component(ofType:)方法:

protocol SpriteComponentProtocol {
    var spriteNode: SKSpriteNode { get set }
}

class PlayerControlComponent: GKComponent {

    override func update(deltaTime seconds: TimeInterval) {
        let comp = self.entity?.component(ofType: SpriteComponentProtocol.self)
    }
}

现在GKEntity满足let comp = self.entity?.component(ofType: (GKComponent & SpriteComponentProtocol).self) 约束。然后,您可以在未打包的实例上访问T方法和: GKComponent协议要求。