Разширение на протокола, мутираща функция

Използвам 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
    }
}

По-късно в моя код се опитвам да извикам този метод и получавам грешка, която гласи:

"не може да използва мутиращ член на неизменна стойност: 'self' е неизменен"

Кодът е както следва:

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

Единственото нещо, за което мога да се сетя, е, че "Self" в този случай е протокол, а не клас. Въпреки това трябва да ми липсва нещо, за да накарам тази концепция да работи, внедряване по подразбиране на метод, дефиниран от протокол, който редактира стойности, дефинирани също от същия протокол.

Благодаря ви за помощта и отделеното време :)


person CWineland    schedule 09.09.2015    source източник


Отговори (2)


Ако възнамерявате да използвате протокола само за класове, можете да го направите протокол за клас (и да премахнете ключовата дума mutating):

protocol ColorImpressionableProtocol : class {

    // ...

    func adoptColorsFromImpresion(impresion: ColorImpressionableProtocol?)
}

Тогава

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

компилира без проблеми.

person Martin R    schedule 09.09.2015
comment
Вярвам, че това е правилният синтаксис за това, което се опитвам да направя, Perfecto! Благодаря ти - person CWineland; 10.09.2015
comment
Трябва да попитам това заради здравия разум ... какво друго може да имплементира протокол освен клас, срещу какво се предпазва това? Просто не виждам друг резултат освен клас, който да отговаря на него - person CWineland; 10.09.2015
comment
@CWineland: протоколите могат да бъдат реализирани и от структура. - person Martin R; 10.09.2015

Вие приемате този протокол в клас, така че себе си (което е референтен тип) е неизменно. Компилаторът очаква 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) Уверете се, че само типове стойности приемат този протокол. Това може да не е полезно във всички сценарии.

Ето подробното обяснение и решение за този случай.

person Abhijith    schedule 20.07.2017