I have checked all answers about this problem on stackoverflow, but still can not figure out how to fix this. My model looks like this
protocol Commandable: Eq
What you need to do is to use type erasure, much like AnyHashable
does in the Swift Standard Library.
You can't do:
var a: [Hashable] = [5, "Yo"]
// error: protocol 'Hashable' can only be used as a generic constraint because it has Self or associated type requirements
What you have to do is to use the type-erased type AnyHashable
:
var a: [AnyHashable] = [AnyHashable(5), AnyHashable("Yo")]
a[0].hashValue // => shows 5 in a playground
So your solution would be to first split the protocol in smaller parts and promote Equatable
to Hashable
(to reuse AnyHashable
)
protocol Conditionable {
var condition: Condition? { get set }
}
protocol Executable {
func execute() -> SKAction
}
protocol Commandable: Hashable, Executable, Conditionable {}
Then create an AnyCommandable
struct, like this:
struct AnyCommandable: Commandable, Equatable {
var exeBase: Executable
var condBase: Conditionable
var eqBase: AnyHashable
init(_ commandable: T) where T : Equatable {
self.condBase = commandable
self.exeBase = commandable
self.eqBase = AnyHashable(commandable)
}
var condition: Condition? {
get {
return condBase.condition
}
set {
condBase.condition = condition
}
}
var hashValue: Int {
return eqBase.hashValue
}
func execute() -> SKAction {
return exeBase.execute()
}
public static func ==(lhs: AnyCommandable, rhs: AnyCommandable) -> Bool {
return lhs.eqBase == rhs.eqBase
}
}
And then you can use it like this:
var a = FunctionCommand()
a.commands = [AnyCommandable(MoveCommand()), AnyCommandable(FunctionCommand())]
And you can easily access properties of commands
, because AnyCommandable
implements Commandable
a.commands[0].condition
You need to remember to now add Hashable
and Equatable
to all your commands.
I used those implementations for testing:
struct MoveCommand: Commandable {
var movingVector: CGVector!
var condition: Condition?
func execute() -> SKAction {
return SKAction()
}
var hashValue: Int {
return Int(movingVector.dx) * Int(movingVector.dy)
}
public static func ==(lhs: MoveCommand, rhs: MoveCommand) -> Bool {
return lhs.movingVector == rhs.movingVector
}
}
struct FunctionCommand: Commandable {
var commands = [AnyCommandable]()
var condition: Condition?
func execute() -> SKAction {
return SKAction.group(commands.map { $0.execute() })
}
var hashValue: Int {
return commands.count
}
public static func ==(lhs: FunctionCommand, rhs: FunctionCommand) -> Bool {
return lhs.commands == rhs.commands
}
}