2017-02-22 6 views
0

できるだけシンプルに作成し、問題の集計をします。 exempleのために、私は自動生成の束クラスメソッドを持つクラスを持っているジェネリックパラメータを使用して関数に「オプションのアンラッピング」を実行する方法

func doSomething<T>(using f: (String, (T) -> Void) -> Void, key: String) { 
    f("test", { 
     object in 
     // do something with object using key 
     //... 
    }) 

} 

を::

のは、私は次のように定義された機能を持っているとしましょう

class MyClass { 
    var prop1: String = "" 
} 

class MyClassAPI { 

    class func f1(param: String, completion: (MyClass) -> Void) { 
     let mc = MyClass() 
     mc.prop1 = "hello" 
     completion(mc) 
    } 
} 

を次に、I

// Any because of cast problem ! 
let keyFunctions: [String: Any] = [ 
    "first" : MyClassAPI.f1, 
    "second" : MySecondClassAPI.f2, 
    "third" : MyThirdClassAPI.f3 
    //... 
] 

最後に、すべてのキー/ fを繰り返します

for (k, f) in keyFunctions { 
    // This line doesn't work as the compiler complain about typing errors 
    doSomething(using: f, key: k) 
} 

私が直面してる問題は、私はdoSomethingにそれらを渡すために右のタイプに私の機能をキャストすることができないということです:f as! (String, (_) ->()) -> Voidを使用してキャストを強制すると仮定

Xcodeは、次に示しますdoSomethingを呼び出すための慰め私はエラー、_はタイプではありません。

if let uf = f as? (String, (Any) -> Void) -> Voidを使用すると、より寛大になりました。

これを達成するためのヒントなしにSwiftマニュアルの全般的なページを読みました。

一般性を使用してそのようなことを実行する既存の方法を教えてください。

+0

これらは高いkindedタイプと呼ばれています。スイフトはそれらをサポートしていません。 – Alexander

+1

辞書の 'f1'、' f2'、 'f3'関数は別のクラスを返しますか?彼らは少なくとも同じプロトコルに準拠することができますか? – Dmitry

+0

@ Dimitryいいえ、それらは異なるクラスから返されません。実際、そのパラメータの1つはクロージャであり、それぞれが異なる型をパラメータとして取ります。 私はそれらをプロトコルに準拠させる必要があると思います。 – dulgan

答えて

1

代わりのAnyブロック

let keyFunctions: [String: (String) -> Any] 

のためのより具体的な形を作る次に、少なくとも、あなたはコンパイルしますとdoSomethingが呼び出されます。 しかし、Tは常にAnyになるので、それを一般化することに意味はありません。 doSomethingがクラス間の共通の振る舞いに依存している場合は、すべてのプロトコルを定義することが理にかなっています。

あなたが実際にあなたのクラスに関する情報を持つようにしたい場合は、この情報を続けるだろう非ジェネリッククラスを導入することができます

class Wrap { 
    var resultType: Any.Type 
    let f: (String) -> Any 

    init<T>(_ f: @escaping (String) -> T) { 
     self.f = f 
     resultType = T.self 
    } 
} 

let keyFunctions: [String: Wrap] = [ 
    "first" : Wrap(MyClassAPI.f1), 
    "second" : Wrap(MySecondClassAPI.f2) 
] 

しかしresultTypeは、後にかかわらず、鋳造に使用することはできません。

+0

私はそれにショットをつけますdoSomething関数で適切なパラメータを使って関数を呼び出せるとは思いません。 実際の問題に近づくようにコードを変更しました。何か変わったかどうか教えてください。 – dulgan

+0

完成ブロック内のオブジェクトのクラスを実際には知る必要がないので、編集された質問を参照)、ラッパーのアイデアに+1 – dulgan

0

私は最終的に、このようにそれを作った:

func doSomething<T>(using f: (String, (Any) -> Void, key: String, type: T.Type) -> Void, key: String) { 
    f("test", { 
     object in 
     guard let o as? type else { return } 
     // do something with o using key 
     //... 
    }) 
} 

let keyFunctions: [String: (String, (Any) -> Void)] = [ 
    "first" : MyClassAPI.f1, 
    "second" : MySecondClassAPI.f2, 
    "third" : MyThirdClassAPI.f3 
    //... 

]

関連する問題