swift - 在 Swift 中,为给定基类的未指定子类创建“包装器”子类的语法是什么?
问题描述
这让我发疯了,因为我觉得它应该是可能的,但无论我如何表达这个想法,我都无法让编译器满意......
我正在做一个 SpriteKit 项目。其中一个类是 SKSpriteNode 的包装器,用于添加精灵在被触摸时调用的动作:
class TouchableSprite: SKSpriteNode {
/// The action to run upon touch
var action: (() -> Void)? = nil
/// Make the sprite react to touches
override var isUserInteractionEnabled: Bool {
get { return true }
set {}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
action?()
}
}
一切都很好。现在我想要一个具有相同功能的 SKLabelNode。只是复制代码但使用 SKLabelNode 可以工作,但我认为我应该能够拥有一个适用于任何各种 SKNode 子类的通用包装器。所以...
class Touchable<T>: T where T: SKNode { ...
不,从非协议、非类类型“T”继承。
class Touchable<T: SKNode>: T { ...
同样的交易......哦,我知道!
class Touchable: T where T: SKNode { ...
至少这是一个不同的错误:“where”子句不能附加到非泛型声明。
class Touchable<T>: T where <T: SKNode> { ...
不,闭包表达式未使用。在经历了无数次不同的尝试之后,我觉得自己是世界上最大的白痴,不得不问如何写这个,但我真的很想知道。
哦,我还认为 SpriteKit 的类层次结构可能有些奇怪(因为双重 Swift/Objective C 支持),所以我还尝试了仅使用纯 Swift 类的各种排列。
class Base {
}
class Wrapper<T: Base>: T {
}
相同的消息数组;我只是无法做到这一点。有人可以告诉我如何表达这个想法,或者至少告诉我为什么不可能。
编辑:至少对于我有节点层次结构的 SpriteKit,我目前的解决方法是将包装器添加为父节点:
class Touchable: SKNode {
let action: () -> Void
init(_ child: SKNode, _ action: @escaping () -> Void) {
self.action = action
super.init()
name = "touchable" + (child.name ?? "")
addChild(child)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented by Touchable")
}
override var isUserInteractionEnabled: Bool {
get { return true }
set {}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
action()
}
}
然后我做任何我想包装的东西,而不是addChild(...)
我做的addChild(Touchable(wrapMe) { ... })
。没关系,但没有我想要的那么干净。
解决方案
这在 Swift 或 ObjC 中是不可能的。您正在尝试创建多重继承,这是不允许的。扩展不能覆盖方法,所以你不能通过扩展来做到这一点。你不能让一个类型继承自 SKSpriteNode 和“提供覆盖的其他类型(即 Touchable)”。而且你不能(安全地)将 Touchable 插入到 SKSpriteNode 的超类链中(你实际上可以使用运行时,但不要这样做;你可以很容易地以意想不到的方式破坏系统的其余部分)。
您的“解决方法”实际上是执行此操作的正确方法。这不是一种解决方法。这只是作曲,而且很好。如果您觉得使用不方便,我们可以谈谈;如果这是一个问题,使用扩展来改进调用语法可能很简单。
推荐阅读
- python-3.x - Django Unitest 注册基于类的视图
- reactjs - 如何正确输入我的反应上下文提供者?
- python - 在 kivy 中显示列表
- r - 如何对一个数据框中的列值求和并将结果添加为另一个数据框中的列?
- java - 如何使用 SQS 事件对 aws lambda 进行单元测试
- docker - 拥有非 root 用户时的文件所有者
- c# - VSCode 未显示 MonoDevelop/Unity/C# 的建议代码
- c# - 无法访问已处置的对象。对象名称:AspNet Core/EF Core 项目中的“IServiceProvider”错误
- python - 无法按分位数选择 Pandas DataFrame
- discord.py - 我怎样才能制作一个禁止 dm 用户的机器人?