私は、クロージャが汎用引数を受け取るオプションのクロージャ引数を使ってメソッドを呼び出す必要があるシナリオを持っています。私はここで何をしようとしている複雑な一般的な引数を持つスウィフトクロージャ
class FooModel
{
}
class FooSubClass1 : FooModel
{
}
class FooSubClass2 : FooModel
{
}
class Client
{
func httpGet<T:FooModel>(closure:((T) -> Void)? = nil)
{
// Doing some network request stuff here and call onHTTPRequestComplete() when done!
onHTTPRequestComplete(data: result, closure: closure)
}
func onHTTPRequestComplete<T:FooModel>(data:[String:Any], closure:((T) -> Void)? = nil)
{
if let c = closure
{
switch(T)
{
case is FooSubClass1:
var foo = FooSubClass1()
// Process data into new FooSubClass1 object here!
c(foo)
case is FooSubClass2:
var foo = FooSubClass2()
// Process data into new FooSubClass2 object here!
c(foo)
}
}
}
}
class App
{
func someFunc()
{
client.httpGet()
{
response in
print("\(response)")
}
}
}
: 私はスーパークラスといくつかのサブクラスを持つデータモデルを持ってここに私の簡略化されたコードです。 Client
私はデータを取得するためにhttpリクエストを行い、取得されたデータでモデルオブジェクトを設定したいと思います。 App
の呼び出しメソッドは、非同期ネットワーク要求が完了し、正しいデータモデルオブジェクトを取得した後に呼び出されるクロージャを提供できる必要があります。
私のコードを持ついくつかの問題があります。
switch(T)
:エラー:予想されるメンバー名またはコンストラクタ呼び出しが
c(foo)
タイプ名の後に:エラー: '(FooSubClass1) - >ボイドは' 'に変換できません(T) - > Void '
私の閉包の定義が私がしようとしていることに合っているかどうかはわかりません。
更新コード:
protocol FooModel
{
init()
}
class FooModelBase : FooModel
{
}
class FooSubClass1 : FooModelBase
{
}
class FooSubClass2 : FooModelBase
{
}
class Client
{
func httpGet<T:FooModel>(closure:((T) -> Void)? = nil)
{
// Doing some network request stuff here and call onHTTPRequestComplete() when done!
onHTTPRequestComplete(data: result, closure: closure)
}
func onHTTPRequestComplete<T:FooModel>(data:[String:Any], closure:((T) -> Void)? = nil)
{
if let c = closure
{
switch T.self
{
case is FooSubClass1.Type:
var foo = FooSubClass1()
// Assign retrieved values to model!
closure(foo)
case is FooSubClass2.Type:
var foo = FooSubClass2()
// Assign retrieved values to model!
closure(foo)
default:
break
}
}
}
}
class App
{
func someFunc()
{
client.httpGet()
{
response in
print("\(response)") // Should output FooSubClass1 instance with assigned values!
}
}
}
ほとんど動作しますが、私は以下のコンパイルエラーを取得:もちろんswitch(T)
エラーのため
'closure(foo): Error: '(@lvalue FooSubClass1) -> Void' is not convertible to '(T) -> Void'
あなたのため、これはまだ動作しません。クロージャーは一般的なTを取る必要があります。代わりに '((FooModel) - > Void)? 'のようなものが必要です(この時点でジェネリックスを取り除くことができます)が、クロージャーでは適切にキャストする必要がありますそれは、そうです。 (これを解決するための多くの方法、つまり別のパラメータを渡して、それがどのような型かを知るなど) – TNguyen
@BadmintonCatジェネリックパラメータの型を扱うswitch文を書くと、ジェネリックは_abstraction_です。 'T'を使用するメソッドは、メソッド内で定義した狭いリストだけでなく、' T'を取ることができなければなりません。私の意見では、すべてを考え直す。 –
最小限のもの:https://pastebin.com/0WDWh1Cb –