Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
199 views
in Technique[技术] by (71.8m points)

ios - Swift: Failed to assign value to a property of protocol?

Class A provides a string value. Class B has two members of A type inside itself, and provide a computed property "v" to choose one of them.

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
        }
    }
}

This code is simple and it works. Since both the A and B have a member "value", I make it a protocol like this:

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
        }
    }
}

If I change the following code

v.value = newValue

to

var v = self.v
v.value = newValue

It works again!

Is this a bug of Swift, or something special for the property of protocols?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You have to define the protocol as a class protocol:

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

Then

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

compiles and works as expected (i.e. assigns the new value to the object referenced by v1 if v1 != nil, and to the object referenced by v2 otherwise).

v is a read-only computed property of the type ValueProvider. By defining the protocol as a class protocol the compiler knows that v is a reference type, and therefore its v.value property can be modified even if the reference itself is a constant.

Your initial code example works because there the v property has the type A which is a reference type.

And your workaround

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

works because (read-write) properties of variables can be set in any case (value type or reference type).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...