我不得不在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有关。
答案 0 :(得分:3)
导致此错误的问题,如@dan has pointed out,就是在此行上您尝试将类型作为参数传递,而不是该类型的实例:
get { return _getNewState(UIState<[T]>) }
但是,我首先会质疑你对这个函数使用一个参数,肯定一个get函数根本就没有参数?在这种情况下,您只需要让_getNewState
函数具有签名() -> UIState<[T]>
,并将其称为:
get { return _getNewState() }
此外,如果您的协议扩展程序中的getNewState
和setNewState(_:)
函数仅用于将state
属性的获取和设置转发到类型擦除 - 您可以简化你的代码完全去除它们并在类型擦除init
中使用闭包表达式:
_getNewState = { models.state }
_setNewState = { models.state = $0 }
(这些工作通过捕获对models
参数的引用,有关详细信息,请参阅Closures: Capturing Values)
最后,我怀疑你的意思是在整个代码中引用UIState<T>
而不是UIState<[T]>
,因为T
在这种情况下引用数组中的元素{{1 case有一个关联值(除非你想要一个2D数组)。
总而言之,通过上面提出的更改,您希望代码看起来像这样:
.Success