связанная ошибка соответствия протоколу swift 2.0

Мне известно об этом сообщении, в котором представлена ​​та же проблема, что и у меня, но оставшийся без ответа и старый, поэтому я решил обновить его здесь.

//: Playground - noun: a place where people can play
import UIKit

protocol BaseViewModel { }

protocol SomeCellViewModelInterface : BaseViewModel { }
protocol AnotherCellViewModelInterface : BaseViewModel { }

protocol BaseCell {

    typealias T
    func configure(viewmodel: T)
}

//

class someCell : UIView, BaseCell {
    typealias T = SomeCellViewModelInterface
    func configure(viewmodel: T) {
        // awesome
    }
}

class someOtherCell : UIView, BaseCell {
    typealias T = AnotherCellViewModelInterface
    func configure(viewmodel: T) {
        // do stuff
    }
}


// the concrete implementations of viewmodels and actually using this UI is ultimatley in another .framework

class ConcreteSomeCellVM : SomeCellViewModelInterface { }
class ConcreteAnotherCellVM : AnotherCellViewModelInterface { }

var viewModel = ConcreteSomeCellVM()

let views: [UIView] = [someCell(), someOtherCell(), UIView()]

Это элементарный пример того, что мне нужно, но он иллюстрирует суть

for v in views {

    // A
    if let cell = v as? someCell {
        cell.configure(viewModel)
    }

    // B
    if let cell = v as? BaseCell {
        cell.configure(viewModel)
    }  
}

Блок A работает, но ему нужно знать конкретный класс ячеек, поэтому, если у меня есть список множества разных ячеек, некоторые из них, для которых я не знаю конкретного типа, не будут работать.

Блок B выдает эту ошибку:

ошибка: протокол «BaseCell» может использоваться только в качестве общего ограничения, поскольку он имеет требования к Self или связанному типу

Есть ли способ достичь блока B?


person cream-corn    schedule 29.10.2015    source источник


Ответы (2)


Есть ли способ достичь блока B?

Я так не думаю. Представьте, что вы компилятор, и подумайте, как бы вы создали код для configure в BaseCell.

  • Какой тип Т?
  • Как бы вы вызвали configure для экземпляра BaseCell, зная, что на самом деле это может быть someCell или someOtherCell, каждый из которых ограничивает параметр другим типом? Например

    func doSomethingWithACell(foo: BaseCell)
    {
        foo.configure(??? what can you put here?)
    }
    

Чтобы достичь того, чего вы действительно хотите, я думаю, вам нужно избавиться от псевдонима типа и сделать объявление следующим образом:

protocol BaseCell {
    func configure(viewmodel: BaseViewModel)
}

В каждом из ваших классов вам нужно будет обрабатывать случай, когда viewModel имеет неправильный тип.

person JeremyP    schedule 29.10.2015
comment
да, чем больше я смотрю на это, тем больше я думаю, что это невозможно в Swift, если бы у вас были общие интерфейсы protocol Something<T> - person cream-corn; 29.10.2015

Я публикую обновление того, что я придумал до сих пор, своего рода ответ, хотя это не идеально, я изменил метод настройки, чтобы он выглядел следующим образом: func configure<T where T : BaseViewModel>(viewmodel: T)

так что, когда я настраиваю эти представления, мне не нужно знать конкретный класс для каждого:

 for v in views {    
    if let cell = v as? BaseCell {
        cell.configure(viewModel)
    }
 }

предостережение заключается в том, что ваши конкретные ячейки должны отображать тип модели представления:

func configure<T : BaseViewModel>(viewmodel: T) {
    if let vm = viewmodel as SomeCellViewModelInterface {
        vm.doSomething()
    }
}

что лучше, но все же не идеально, потому что приведение по-прежнему должно происходить в ячейке.

person cream-corn    schedule 02.11.2015