简体   繁体   中英

Protocol Extension, Mutating Function

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 :)

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM