使用通用枚举和通用协议进行快速类型擦除

dam*_*ban 5 generics ios swift swift-protocols swift2

我不得不在 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
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的类型擦除泛型类:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

我收到以下错误(它们在代码示例中标记):

错误#1:

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

我已经为此工作了一段时间,并且该代码有很多“几乎有效”的变体。错误总是与吸气剂有关。

Ham*_*ish 3

正如@dan 所指出的,导致此错误的问题是,在这一行中,您尝试传递一个类型作为参数,而不是该类型的实例:

\n\n
get { return _getNewState(UIState<[T]>) }\n
Run Code Online (Sandbox Code Playgroud)\n\n

但是,我首先会质疑您对该函数的参数的使用,肯定获取函数根本不应该有参数吗?在这种情况下,您只希望您的_getNewState函数具有签名() -> UIState<[T]>,并像这样调用它:

\n\n
get { return _getNewState() }\n
Run Code Online (Sandbox Code Playgroud)\n\n

另外,如果协议扩展中的getNewStatesetNewState(_:)函数只是为了将属性的获取和设置转发state到类型擦除 \xe2\x80\x93 而存在,那么您可以通过完全摆脱它们并使用闭包表达式来简化代码类型擦除的init

\n\n
_getNewState = { models.state }\n_setNewState = { models.state = $0 }\n
Run Code Online (Sandbox Code Playgroud)\n\n

(这些通过捕获对参数的引用来工作models,有关更多信息,请参阅闭包:捕获值

\n\n

最后,我怀疑您的意思是引用UIState<T>而不是UIState<[T]>在整个代码中,因为T在本例中指的是您的数组中的元素.Success在本例中指的是您的案例作为关联值的

\n\n

总而言之,通过上述建议的更改,您将希望您的代码如下所示:

\n\n
enum UIState<T> {\n    case Loading\n    case Success([T])\n    case Failure(ErrorType)\n}\n\nprotocol ModelsDelegate: class {\n    associatedtype Model\n    var state: UIState<Model> { get set }\n}\n\nclass AnyModelsDelegate<T>: ModelsDelegate {\n    var state: UIState<T> {\n        get { return _getNewState() }\n        set { _setNewState(newValue) }\n    }\n\n    private let _getNewState: () -> UIState<T>\n    private let _setNewState: (UIState<T>) -> Void\n\n    required init<U: ModelsDelegate where U.Model == T>(_ models: U) {\n        _getNewState = { models.state }\n        _setNewState = { models.state = $0 }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n