Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/99.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 强制模板成为协议_Ios_Swift_Generics_Protocols - Fatal编程技术网

Ios 强制模板成为协议

Ios 强制模板成为协议,ios,swift,generics,protocols,Ios,Swift,Generics,Protocols,如何确保给定的模板参数是协议 一个gk实体有一个名为component(of type:class)的函数,我想添加组件(of Protocol:Protocol)。它确实是这样的: extension GKEntity { func component<T: Protocol>(ofProtocol: T) -> T? { return self.components.first() { component in return

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

一个
gk实体
有一个名为
component(of type:class)
的函数,我想添加
组件(of Protocol: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)
    }
}

我希望能够随时交换SpriteComponentProtocol。

您的代码的问题是
协议
是一种描述Obj-C协议的不透明类型,因此如果您想将
SpriteComponentProtocol.self
桥接到它,您需要将
SpriteComponentProtocol
标记为
@objc
(但即使您这样做了,您也无法强制转换到
t
,因为返回的实例不是
协议类型的

但是也就是说,您不需要在这里使用Obj-C
协议
类型或
符合(to:)
方法,您只需在
组件(ofType:)
的重载中使用条件类型转换操作符
as?
,而不需要
GKComponent
t
的约束:

extension GKEntity {

    func component<T>(ofType type: T.Type) -> T? {
        return self.components.lazy.flatMap{ $0 as? T }.first
    }
}
在Swift 4中,您可以完全删除此重载,而只需使用类存在元类型调用
GKEntity
的方法:

let comp = self.entity?.component(ofType: (GKComponent & SpriteComponentProtocol).self)

现在,
T
满足了
:GKComponent
约束。然后,您可以访问
GKComponent
方法和
SpriteComponentProtocol
对未包装实例的协议要求。

因此,我们可以这样做:
self.entity?.component(protocol:SpriteComponentProtocol.self)as?SpriteComponentProtocol
如果我返回一个
GKComponentProtocol
而不是模板T,并将objc引用添加到协议中,这需要objc导出,对吗?我的想法是,我对固定类没有要求。相反,我希望它是一个协议,这样我就可以轻松地将其交换到其他内容。非常感谢。我认为这是一个很好的方法,可以确保我以后不会把它搞砸,即使我已经对此进行了测试。我们是否可以将桥默认为
{%0}
closure?这是有道理的。不幸的是,我不太了解swift的一般特性。我认为为此编写测试,并使用不同的方法签名,然后是
组件(ofType…)
应该可以确保没有人尝试添加与其他组件不一致的新组件。太棒了。如果我在没有@objc的情况下传入协议,编译器不会抱怨。你确定我现在必须这样做吗?@BennX正确,
不再需要@objc
let comp = self.entity?.component(ofType: (GKComponent & SpriteComponentProtocol).self)