如何确保给定的模板参数是协议?
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'
更新:
这个想法是我有一个雪碧组件:
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)
}
}
我希望能够随时更换精灵组件。
代码的问题在于Protocol
是描述 Obj-C 协议的不透明类型,因此如果要将SpriteComponentProtocol.self
桥接到它,则需要将SpriteComponentProtocol
标记为@objc
(但即使你这样做了;你也无法强制转换为T
,因为返回的实例不是类型Protocol
(。
但话虽如此,您不需要在此处使用 Obj-CProtocol
类型或conforms(to:)
方法,您只需在component(ofType:)
重载中使用条件类型转换运算符as?
,而无需对T
进行GKComponent
约束:
extension GKEntity {
func component<T>(ofType type: T.Type) -> T? {
return self.components.lazy.flatMap{ $0 as? T }.first
}
}
我们在这里使用lazy
以避免评估所有components
,然后flatMap(_:)
和first
以获得第一个可铸造T
的元素(在T
是协议类型的情况下,这给了我们第一个符合协议的元素(。
然后,您可以像这样简单地使用它:
protocol SpriteComponentProtocol {
var spriteNode: SKSpriteNode { get set }
}
class PlayerControlComponent: GKComponent {
override func update(deltaTime seconds: TimeInterval) {
let comp = self.entity?.component(ofType: SpriteComponentProtocol.self)
}
}
在 Swift 4 中,你可以完全删除这个重载,而是简单地用类存在元类型调用GKEntity
的component(ofType:)
方法:
let comp = self.entity?.component(ofType: (GKComponent & SpriteComponentProtocol).self)
就像现在一样,T
满足: GKComponent
约束。然后,您可以在解包的实例上访问GKComponent
方法和SpriteComponentProtocol
协议要求。