2016-08-12 35 views
3

Swiftでタイプ消去を数回使用しなければならなかったのですが、それはいつも汎用プロトコルを含んでいました。この場合、一般的なenum と汎用プロトコルの両方が関係しており、私は困惑しています。一般的な列挙型と一般的なプロトコルの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

のインスタンスを取るメソッドにタイプを渡していますあなたの 'getNewState'関数が入力を受け取る理由を少し混乱させますが、確かにそれは'() - > UIState <[Model]> 'でなければなりません。 'getNewState'と' setNewState'関数が、あなたの型削除に渡して設定を転送するためだけに存在するとしても、それは必要ではありません。これは、型閉めで型を削除することで直接行うことができます(つまり '_getNewState = state} '&' _setNewState = {models.state = $ 0} ')。 – Hamish

+0

はい私はそれについてもちょっと混乱しています:)。もともと私は入力を取っていないときにエラーを受けていたので、入力が必要です。私はリファクタリングしようとしましょう。 – damianesteban

答えて

2

このエラーが発生する問題は、@dan has pointed outとして、このライン上であなたの代わりに、その型のインスタンスを、引数として型を渡すしようとしているということです。

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

しかし、私は考え最初にこの関数への引数の使用について疑問を呈しますが、関数を取得するには引数が全くないはずです。

get { return _getNewState() } 

をまた、あなたのプロトコル拡張でごgetNewStatesetNewState(_:)機能のみ取得を転送するために存在している場合:この場合、あなたは単に署名() -> UIState<[T]>を持っており、そのようにそれを呼び出すために、あなたの_getNewState機能をお勧めしますそして、型消去にごstateプロパティの設定 - あなたは完全にそれらを取り除くことで、あなたのコードを簡素化し、型消去のinit代わりに閉鎖式を使用することができます。

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

(TH Closures: Capturing Valuesを参照してください詳細は、models引数への参照を取得することにより、ESE作業)

この場合Tはの要素を指す最後に、私は、あなたがあなたのコード全体UIState<T>ではなくUIState<[T]>を参照することを意味することを疑います(ここでは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

関連する問題