Pregunta Swift: ¿Error al asignar valor a una propiedad del protocolo?


La clase A proporciona un valor de cadena. La clase B tiene dos miembros del tipo A en su interior y proporciona una propiedad calculada "v" para elegir uno de ellos.

class A {
    var value: String

    init(value: String) {
        self.value = value
    }
}

class B {
    var v1: A?
    var v2: A = A(value: "2")

    private var v: A {
        return v1 ?? v2
    }

    var value: String {
        get {
            return v.value
        }
        set {
            v.value = newValue
        }
    }
}

Este código es simple y funciona. Dado que tanto A como B tienen un "valor" de miembro, lo hago un protocolo como este:

protocol ValueProvider {
    var value: String {get set}
}

class A: ValueProvider {
    var value: String

    init(value: String) {
        self.value = value
    }
}

class B: ValueProvider {
    var v1: ValueProvider?
    var v2: ValueProvider = A(value: "2")

    private var v: ValueProvider {
        return v1 ?? v2
    }

    var value: String {
        get {
            return v.value
        }
        set {
            v.value = newValue // Error: Cannot assign to the result of the expression
        }
    }
}

Si cambio el siguiente código

v.value = newValue

a

var v = self.v
v.value = newValue

¡Funciona de nuevo!

¿Es esto un error de Swift, o algo especial por la propiedad de los protocolos?


5
2018-04-19 10:43


origen


Respuestas:


Debe definir el protocolo como class protocolo:

protocol ValueProvider : class {
    var value: String {get set}
}

Entonces

var value: String {
    get { return v.value }
    set { v.value = newValue }
}

compila y funciona como se esperaba (es decir, asigna el nuevo valor al objeto referenciado por v1 Si v1 != nily al objeto referenciado por v2 de otra manera).

v es una propiedad computada de solo lectura del tipo ValueProvider. Al definir el protocolo como un protocolo de clase, el compilador sabe ese v es un tipo de referencia, y por lo tanto su v.value la propiedad se puede modificar incluso si la referencia en sí misma es una constante.

Su ejemplo de código inicial funciona porque allí v la propiedad tiene el tipo A que es un tipo de referencia.

Y tu solución

set {
    var tmp = v1 ?? v2
    tmp.value = newValue
}

funciona porque las propiedades (lectura-escritura) de variables se puede establecer en cualquier caso (tipo de valor o tipo de referencia).


10
2018-04-19 11:10