Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Protocol: Cannot assign to 'X' in 'Y' in Swift

I just defined a very simple protocol and a a class using generics which can handle this protocol.

In the lines marked with error you will get the error: "Cannot assign to 'flag' in 'aObj'.

 protocol Flag {
    var flag: Bool {get set}
 }


 class TestFlag<T: Flag>  {

    func toggle(aObj: T) {

        if aObj.flag {
            aObj.flag = false;  // <--- error
        } else {
            aObj.flag = true;   // <--- error
        }
    }
 }

Do you have an idea why and what I have to change to fix it?

like image 457
Stephan Avatar asked Jun 22 '14 19:06

Stephan


People also ask

What is protocol type in Swift?

In Swift, a protocol defines a blueprint of methods or properties that can then be adopted by classes (or any other types). We use the protocol keyword to define a protocol. For example, protocol Greet { // blueprint of a property var name: String { get } // blueprint of a method func message() }

What is use of protocol in Swift?

Protocol is a very powerful feature of the Swift programming language. Protocols are used to define a “blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality.”

Can struct conform to protocol Swift?

In Swift, protocols contain multiple abstract members. Classes, structs and enums can conform to multiple protocols and the conformance relationship can be established retroactively.

What is protocol iOS?

In iOS development, a protocol is a set of methods and properties that encapsulates a unit of functionality. The protocol doesn't actually contain any of the implementation for these things; it merely defines the required elements.


2 Answers

From the docs:

Function parameters are constants by default. Trying to change the value of a function parameter from within the body of that function results in a compile-time error. This means that you can’t change the value of a parameter by mistake.

In this case, you can add inout so that the toggle is persisted beyond your function call:

func toggle(inout aObj: T) {           
   if aObj.flag {
      aObj.flag = false;
   else {
      aObj.flag = true;
   }
}

You could have also done:

func toggle(var aObj: T) { 
}

but that might not achieve what you wanted.

like image 75
manojlds Avatar answered Oct 18 '22 03:10

manojlds


manojlds answer is correct and therefore I accepted it.

Nevertheless there was a similar answer some days ago with the same solution but with a other argumentation (seems now deleted).

The argumentation was about that the compliler can not know if the protocol is used for a class, a struct or a enum. With Swift, protocols can by applied on all this types. But struct instances use a by-value call and for classes instances (objects) it us a by-reference call.

From my perspective this answer was correct too, because you can solve the problem with a 2nd solution:

@objc  
protocol Flag {
    var flag: Bool {get set} 
}

Just add the @obj attriute on the protocol. As a result you can use this protocol only for a class which lead to the result only by-refernece calls are allowd. Therefore the compiler don't need anymore the inout information.

But I searched for a solution to increase the reuse of the protocol and use now manojlds suggestions.

like image 45
Stephan Avatar answered Oct 18 '22 03:10

Stephan