2016-08-12 4 views
3

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

Вот мое общее перечисление и общий протокол с необходимым расширением:

enum UIState<T> { 
    case Loading 
    case Success([T]) 
    case Failure(ErrorType) 
} 

protocol ModelsDelegate: class { 
    associatedtype Model 
    var state: UIState<[Model]> { get set } 
} 

extension ModelsDelegate { 

    func getNewState(state: UIState<[Model]>) -> UIState<[Model]> { 
     return state 
    } 

    func setNewState(models: UIState<[Model]>) { 
     state = models 
    } 
} 

А вот это мой типа стерта общим класс:

class AnyModelsDelegate<T>: ModelsDelegate { 
    var state: UIState<[T]> { 

     get { return _getNewState(UIState<[T]>) } // Error #1 
     set { _setNewState(newValue) } 
    } 

    private let _getNewState: ((UIState<[T]>) -> UIState<[T]>) 
    private let _setNewState: (UIState<[T]> -> Void) 

    required init<U: ModelsDelegate where U.Model == T>(_ models: U) { 
     _getNewState = models.getNewState 
     _setNewState = models.setNewState 
    } 
} 

Я получаю следующие ошибки (они отмеченные в примере кода):

Ошибка № 1:

Cannot convert value of type '(UIState<[T]>).Type' (aka 'UIState<Array<T>>.Type') to expected argument type 'UIState<[_]>' (aka 'UIState<Array<_>>')

Я работаю над этим некоторое время, и на этом коде было довольно много вариаций, которые «почти сработали». Ошибка всегда имеет отношение к геттеру.

+1

Вы пропускание типа к способу, который принимает экземпляр этого типа – dan

+0

I 'm немного запутался, почему ваша функция 'getNewState' принимает вход, конечно, это должен быть'() -> UIState <[Model]> '? Хотя, если ваши функции 'getNewState' и' setNewState' существуют только для пересылки получения и настройки для стирания вашего типа, они не нужны, поскольку вы можете сделать это непосредственно в стирании типа с помощью замыканий (то есть '_getNewState = {models. state} '&' _setNewState = {models.state = $ 0} '). – Hamish

+0

Да, я тоже немного смущен :). Он принимает ввод, потому что изначально я получал ошибки, когда он не принимал ввода. Позвольте мне попробовать рефакторинг. – damianesteban

ответ

2

Проблема, которая вызывает эту ошибку, так как @dan has pointed out, что на этой линии вы пытаетесь передать тип в качестве аргумента, вместо экземпляра этого типа:

get { return _getNewState(UIState<[T]>) } 

Однако, я бы вопрос о том, как использовать аргумент этой функции в первую очередь, наверняка функция получения не должна иметь никаких аргументов? В этом случае вы просто хотите, чтобы ваш _getNewState функцию, чтобы иметь подпись () -> UIState<[T]>, и назвать его так:

get { return _getNewState() } 

Кроме того, если ваши getNewState и setNewState(_:) функции в расширении протокола существует только для того, чтобы переслать получение и настройка вашего state имущества типа стирания - вы можете упростить ваш код, чтобы избавиться от них полностью и использовать закрывающие выражения в тип стирания в init вместо:

_getNewState = { models.state } 
_setNewState = { models.state = $0 } 

(Th ESE работы, захватив ссылку на models аргумент, для получения дополнительной информации см Closures: Capturing Values)

Наконец, я подозреваю, что вы имеете в виду, чтобы обратиться к UIState<T>, а не UIState<[T]> на протяжении всего кода, как T в данном случае относится к элементу в массив, который имеет ваш случай .Success как связанное значение (если вы не хотите, чтобы здесь был 2D-массив).

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

enum UIState<T> { 
    case Loading 
    case Success([T]) 
    case Failure(ErrorType) 
} 

protocol ModelsDelegate: class { 
    associatedtype Model 
    var state: UIState<Model> { get set } 
} 

class AnyModelsDelegate<T>: ModelsDelegate { 
    var state: UIState<T> { 
     get { return _getNewState() } 
     set { _setNewState(newValue) } 
    } 

    private let _getNewState:() -> UIState<T> 
    private let _setNewState: (UIState<T>) -> Void 

    required init<U: ModelsDelegate where U.Model == T>(_ models: U) { 
     _getNewState = { models.state } 
     _setNewState = { models.state = $0 } 
    } 
} 
+0

Отлично. Спасибо. И да, мне не нужен 2D-массив. Это была ошибка с моей стороны, поскольку я пытался работать с ошибками. – damianesteban

+0

@damianesteban С удовольствием помогите :) – Hamish

Смежные вопросы