具有通用枚举和通用协议的Swift类型擦除

时间:2016-08-12 16:09:24

标签: ios swift generics swift2 swift-protocols

我不得不在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<_>>')

我一直在研究这个问题,而且这个代码有很多变化,“几乎可以工作”。错误总是与getter有关。

1 个答案:

答案 0 :(得分:3)

导致此错误的问题,如@dan has pointed out,就是在此行上您尝试将类型作为参数传递,而不是该类型的实例:

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

但是,我首先会质疑你对这个函数使用一个参数,肯定一个get函数根本就没有参数?在这种情况下,您只需要让_getNewState函数具有签名() -> UIState<[T]>,并将其称为:

get { return _getNewState() }

此外,如果您的协议扩展程序中的getNewStatesetNewState(_:)函数仅用于将state属性的获取和设置转发到类型擦除 - 您可以简化你的代码完全去除它们并在类型擦除init中使用闭包表达式:

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

(这些工作通过捕获对models参数的引用,有关详细信息,请参阅Closures: Capturing Values

最后,我怀疑你的意思是在整个代码中引用UIState<T>而不是UIState<[T]>,因为T在这种情况下引用数组中的元素{{1 case有一个关联值(除非你想要一个2D数组)。

总而言之,通过上面提出的更改,您希望代码看起来像这样:

.Success