Search code examples
iosswiftclassreferenceinout

Why does my Xcode compiler tell me I use a value type even though I use classes?


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"...


Solution

  • 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.