协议扩展,变异功能

CWi*_*and 21 iphone protocols ios swift ios9

我正在使用swift 2.0,我在协议上有一个协议和一个扩展来创建一个方法的默认实现,代码就像休闲:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

我稍后在我的代码中试图调用此方法,并收到一条错误,内容如下:

"不能在不可变值上使用变异成员:'self'是不可变的"

代码是休闲:

init(impresion: ColorImpressionableProtocol?){
        super.init(nibName: nil, bundle: nil)
        adoptColorsFromImpresion(impresion)
}
Run Code Online (Sandbox Code Playgroud)

我唯一能想到的是,在这种情况下,"自我"是一个协议,而不是一个类.但是,我必须缺少一些使这个概念起作用的东西,一个由协议定义的方法的默认实现,该协议编辑同样由同一协议定义的值.

谢谢你的帮助和时间:)

Mar*_*n R 43

如果您打算仅将协议用于类,那么您可以将其作为类协议(并删除mutating关键字):

protocol ColorImpressionableProtocol : class {

    // ...

    func adoptColorsFromImpresion(impresion: ColorImpressionableProtocol?)
}
Run Code Online (Sandbox Code Playgroud)

然后

init(impresion: ColorImpressionableProtocol?){
    super.init(nibName: nil, bundle: nil)
    adoptColorsFromImpresion(impresion)
}
Run Code Online (Sandbox Code Playgroud)

编译没有问题.


Abh*_*man 6

您在类中采用此协议,因此self(引用类型)是不可变的。编译器期望self将通过协议中声明的可变方法可变。这就是您收到此错误的原因。

可能的解决方案是:

1)在采用协议的地方实现该方法的一个非变异版本。即:采用类而不是协议扩展来实现该方法。

class MyClass : ColorImpressionableProtocol {

   func adoptColorsFromImpresion(impresion: ColorImpressionableProtocol?){
        lightAccentColor = impresion?.lightAccentColor
        accentColor = impresion?.accentColor
        darkAccentColor = impresion?.darkAccentColor
        specialTextColor = impresion?.specialTextColor
    }
}
Run Code Online (Sandbox Code Playgroud)

2)将该协议设为仅类协议。这样我们就可以删除mutating关键字。这是最简单的解决方案,但只能在课堂上使用。

仅使协议类:

protocol MyProtocolName : AnyObject { }
OR
protocol MyProtocolName : class { }
Run Code Online (Sandbox Code Playgroud)

3)确保仅值类型采用此协议。这可能不适用于所有情况。

是此情况的详细说明和解决方案。