0

I have two classes: Player and Enemy that both conform to the protocol CharacterCharacteristicsProtocol:

class Enemy: CharacterCharacteristicsProtocol {...
class Player: CharacterCharacteristicsProtocol {...

They are both references and not values like structs are; still when I send in the objects as arguments like this:

viewModel.combatButtonIsClicked(attacker: self.player, defender: self.enemy) { result in...

I get the error

Passing value of type 'CharacterCharacteristicsProtocol' to an inout parameter requires explicit '&'

Why is this showing up? Isn't this only supposed to happen with structs?

If I do as the compiler wish and inset inout and & at the appropriate places things work except for in closures where the error now is

Escaping closure captures 'inout' parameter 'characterVM'

Here's where it happens (just for completion):

func enemyTurn(enemyVM: CharacterCharacteristicsProtocol, characterVM: inout CharacterCharacteristicsProtocol, completion: @escaping(_ enemyReponse: String) -> Void){
    let xEnemy = enemyVM.getX()
    let yEnemy = enemyVM.getY()
        
    viewModel.enemyShouldMove = true

    viewModel.proximityCheck(checkProxyForWho: .enemy, i: xEnemy, j: yEnemy, completion: {
        let combat = Combat()
        combat.combat(attacker: enemyVM, defender: &characterVM, completion: { result in...

I have searched on how to solve this error and the get the following suggestion: "change the struct to a class"...

Joakim Sjöstedt
  • 824
  • 2
  • 9
  • 18
  • Check this: https://stackoverflow.com/q/31960117/1187415 – you probably want to declare CharacterCharacteristicsProtocol as a “class protocol” – Martin R Sep 09 '20 at 19:06

1 Answers1

1

Is your protocol class bound? If not, the compiler needs to assume that a struct may also implement it and needs to apply value semantics.
To make a protocol class bound you simply need to do like this:
protocol CharacterCharacteristicsProtocol: class

Then you will only be able to implement it with classess, and not structs, and the compiler will be able to assume that only reference semantics apply.

Losiowaty
  • 7,911
  • 2
  • 32
  • 47
  • 2
    Just a minor side note: `: class` is considered less favorable; `: AnyObject` is a preferred way to limit a protocol adoption to class types. – Vadim Belyaev Sep 09 '20 at 21:08
  • @Losiowaty Ah, ok, I didn't know that. So even though you only use classes you specifically need to resdtrict the protocol. Thanks a bunch for clearing that up! – Joakim Sjöstedt Sep 10 '20 at 06:50
  • @VadimBelyaev Ok, good to know! Could you just elaborate a bit on why it is more favorable to use AnyObject. And doesn't AnyObject incluce structs as well? – Joakim Sjöstedt Sep 10 '20 at 06:51
  • @JoakimSjöstedt, the `: class` is no longer mentioned in the official Swift documentation therefore I'd speculate it may be deprecated eventually. There's a subtle difference between `: class` and `: AnyObject` as discussed here: https://stackoverflow.com/questions/30176814/whats-the-difference-between-a-protocol-extended-from-anyobject-and-a-class-onl/32895975#32895975 In practice the two will have identical behavior in most cases. A struct can't conform to `AnyObject` (compiler will raise an error), therefore a struct can't conform to a class-only protocol declared with `: AnyObject`. – Vadim Belyaev Sep 10 '20 at 20:29