Chris Harper Chris Harper - 7 months ago 25
Swift Question

Swift protocol settable property through a read-only property

Can someone please tell me why Swift has to call the setter of a property when it's only being used to access an object (a protocol) in order to set one of its properties? This first example shows the error I get if I don't declare the indirect object as settable:

protocol AProtocol {
var name: String { get set }
}

class AnImplementation: AProtocol {
var name = ""
}

class AParent {
var test = AnImplementation()
}

class AChild {
var parent: AParent!

var test: AProtocol {
get { return parent.test }
// Note: Not settable
}
}

var parent = AParent()
var child = AChild()
child.parent = parent

child.test.name = "Hello world!" // Error: Cannot assign to property : 'test' is a get-only property
print(child.test.name)


If I give it a setter, it compiles and works but it calls the setter:

protocol AProtocol {
var name: String { get set }
}

class AnImplementation: AProtocol {
var name = ""
}

class AParent {
var test = AnImplementation()
}

class AChild {
var parent: AParent!

var test: AProtocol {
get { return parent.test }
set(newTest) { print("Shouldn't be here!") }
}
}

var parent = AParent()
var child = AChild()
child.parent = parent

child.test.name = "Hello world!"
print(child.test.name)


Output is:

Shouldn't be here!
Hello world!


I'm not sure what I'm not understanding here. I assume I can just give it an empty setter, but I'd like to understand the reason for it.

Any information is much appreciated!

Answer

Change your protocol declaration to this:

protocol AProtocol:class {
    var name: String { get set }
}

Otherwise, it is taken by default as a value type. Changing a value type's property replaces the value type instance (as shown by the setter observer). And you can't do that if the reference is a let reference.