Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Protocol Extension, Mutating Function

Tags:

I am using swift 2.0, I have a protocol and an extension on the protocol to create a default implementation of a method, the code is as fallows:

protocol ColorImpressionableProtocol {      var lightAccentColor: UIColor? {get set}     var accentColor: UIColor? {get set}     var darkAccentColor: UIColor? {get set}     var specialTextColor: UIColor? {get set}      mutating func adoptColorsFromImpresion(impresion: ColorImpressionableProtocol?) }  extension ColorImpressionableProtocol {      mutating func adoptColorsFromImpresion(impresion: ColorImpressionableProtocol?){         lightAccentColor = impresion?.lightAccentColor         accentColor = impresion?.accentColor         darkAccentColor = impresion?.darkAccentColor         specialTextColor = impresion?.specialTextColor     } } 

I am later on in my code trying to call this method and am getting an error that reads:

"cannot use mutating member on immutable value:'self' is immutable"

The code is as fallows:

init(impresion: ColorImpressionableProtocol?){         super.init(nibName: nil, bundle: nil)         adoptColorsFromImpresion(impresion) } 

The only thing I can think of is that 'Self' in this case is a protocol, not a class. However I have to be missing something to make this concept work, A default implementation of a method defined by a protocol that edits values also defined by the same protocol.

Thank you for your help and time :)

like image 804
CWineland Avatar asked Sep 09 '15 20:09

CWineland


People also ask

What is a mutating function?

What can a mutating function do? Essentially, a function that's been marked as mutating can change any property within its enclosing value. The word “value” is really key here, since Swift's concept of structured mutations only applies to value types, not to reference types like classes and actors.

What is protocol extension?

Protocols let you describe what methods something should have, but don't provide the code inside. Extensions let you provide the code inside your methods, but only affect one data type – you can't add the method to lots of types at the same time.

Why do we use the mutating keyword?

The mutating keyword lets callers know that the method is going to make the value change. The best way to conceptualize this is to think of your struct the same as you would a number: if you perform the operation 4 + 1, 4 doesn't become 5, you've just gotten a new value after performing the operation.

How many protocols can a Swift class adopt?

Swift 4 allows multiple protocols to be called at once with the help of protocol composition.


2 Answers

If you intend to use the protocol only for classes then you can make it a class protocol (and remove the mutating keyword):

protocol ColorImpressionableProtocol : class {      // ...      func adoptColorsFromImpresion(impresion: ColorImpressionableProtocol?) } 

Then

init(impresion: ColorImpressionableProtocol?){     super.init(nibName: nil, bundle: nil)     adoptColorsFromImpresion(impresion) } 

compiles without problems.

like image 56
Martin R Avatar answered Oct 18 '22 15:10

Martin R


You are adopting this protocol in a class so the self (which is reference type) is immutable. The compiler expects self to be mutable because of the mutable method declared in protocol. That's the reason you are getting this error.

The possible solutions are :

1) Implement a non mutating version of the method where the protocol being adopted. ie: implement the method in adopting class instead as a protocol extension.

class MyClass : ColorImpressionableProtocol {     func adoptColorsFromImpresion(impresion: ColorImpressionableProtocol?){         lightAccentColor = impresion?.lightAccentColor         accentColor = impresion?.accentColor         darkAccentColor = impresion?.darkAccentColor         specialTextColor = impresion?.specialTextColor     } } 

2) Make the protocol as class only protocol. This way we can remove the mutating keyword. It's the easiest solution but it can be only used in class.

To make protocol class only :

protocol MyProtocolName : AnyObject { } OR protocol MyProtocolName : class { } 

3) Make sure only value types adopt this protocol.This may not be useful in all scenarios.

Here is the detailed explanation and solution for this case.

like image 45
Abhijith Avatar answered Oct 18 '22 15:10

Abhijith