web-dev-qa-db-ja.com

プロトコル拡張、変異機能

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

後でコードでこのメソッドを呼び出そうとすると、次のようなエラーが発生します。

「不変の値に変更メンバーを使用できません:「自己」は不変です」

コードは休閑中です:

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

私が考えることができる唯一のことは、この場合の「Self」はプロトコルであり、クラスではないということです。ただし、この概念を機能させるには、何かが欠けている必要があります。同じプロトコルで定義された値を編集するプロトコルで定義されたメソッドのデフォルトの実装です。

あなたの助けと時間をありがとう:)

22
CWineland

クラスにのみプロトコルを使用する場合は、それをクラスプロトコルにすることができます(そしてmutatingキーワードを削除します):

protocol ColorImpressionableProtocol : class {

    // ...

    func adoptColorsFromImpresion(impresion: ColorImpressionableProtocol?)
}

次に

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

問題なくコンパイルできます。

43
Martin R

クラスでこのプロトコルを採用しているため、自己(参照型)は不変です。コンパイラは、プロトコルで宣言された可変メソッドのために、selfが可変であることを期待しています。これが、このエラーが発生する理由です。

考えられる解決策は次のとおりです。

1)プロトコルが採用されているメソッドの非変更バージョンを実装します。つまり、プロトコル拡張として代わりにクラスを採用するメソッドを実装します。

class MyClass : ColorImpressionableProtocol {

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

2)プロトコルをクラスのみのプロトコルにします。このようにして、mutatingキーワードを削除できます。これは最も簡単な解決策ですが、クラスでのみ使用できます。

プロトコルクラスのみを作成するには:

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

3)値型のみがこのプロトコルを採用していることを確認してください。これは、すべてのシナリオで役立つとは限りません。

ここ はこの場合の詳細な説明と解決策です。

7
Abhijith