2017-03-08 2 views
0

私は、パラメータとしてクロージャを受け取り、クラスのインスタンスを作成してそれをクロージャに渡すジェネリッククラスの静的メソッドを作成しようとしています。キャッチは、これをサブクラス化して、クロージャが私が使用するサブクラスに確実に従うようにしたいということです。Swift 3:静的なクラス関数を宣言して、クロージャの種類をSelfに制限する方法はありますか?

私はあなたが静的メソッドの戻り値の型として「自己」を使用することができることを知っているが、私はメソッドのヘッダでそれを使用しようとすると、私は次のエラーを取得する:

"'Self' is only available in a protocol or as the result of a method in a class"

私は思いますこのような何かをしたい:他に

class GenericClass: NSObject { 
    required override init() { 
     super.init() 
    } 

    static func createAndExecuteAsync(block: (Self) -> Void) { 
     DispatchQueue.global().async { 
      let instance = self.init() 
      block(instance) 
     } 
    } 
} 

class OtherClass: GenericClass { 
    // ... 
} 

どこかで...

OtherClass.createAndExecuteAsync { (instance: OtherClass) in 
    // Do stuff to instance 
} 

UPDATE:

Hamishのソリューションthis postのおかげで、私は解決策に近づいています。自分のジェネリッククラスのプロトコルを最初に作成しておけば、自分が望むやり方でSelfを使うことができます。しかし、それは私の状況にとって望ましくない、OtherClassを最終的にすることを強いる。

最終OtherClassせずに、私は次のエラーを取得する:

Protocol 'GenericClass' requirement 'createAndExecuteAsync(block:)' cannot be satisfied by a non-final class ('OtherClass') because it uses 'Self' in a non-parameter, non-result type position.

は、ここでそれがどのように見えるかです:

protocol GenericClass { 
    init() 
    static func createAndExecuteAsync(block: @escaping (Self) -> Void) 
} 

extension GenericClass { 
    static func createAndExecuteAsync(block: @escaping (Self) -> Void) { 
     DispatchQueue.global().async { 
      let instance = self.init() 
      block(instance) 
     } 
    } 
} 

final class OtherClass : GenericClass { 
    var myProperty = 1 

    required init() { } 
} 

// Somewhere else... 
OtherClass.createAndExecuteAsync { (instance) in 
    instance.myProperty = 2 
} 
+0

強く関連する(だます):[INIT paramsはセルフ](http://stackoverflow.com/q/40055862/2976878)。 [私の答え](http://stackoverflow.com/a/42356615/2976878)に示すように、プロトコルを使用して、そのプロトコルの拡張部に 'createAndExecuteAsync'メソッドを置くことができます。しかし、最終的に、これがプロトコル拡張の外では不可能であるべき本当の理由はありません。 – Hamish

+0

@ハミッシュそのポストであなたのソリューションに私を指摘していただきありがとうございます。それは私に理想的ではない最終的なクラスを使用するよう強制されますが、それは私を解決に近づけます。 – Mel

+0

ああ、それは私の答えで言及したような荒いエッジです。プロトコルの要件から 'createAndExecuteAsync'を削除して、拡張でしか持たないといけません。それはあなたのコードが非最終的なクラスでコンパイルできるようにすべきです:) – Hamish

答えて

0

おそらく、あなたがわずかに異なる使用構文でグローバルな汎用関数を使用することができます。例えば

func createAndExecuteAsync<T:GenericClass>(_ objectType:T.Type, _ block:@escaping (T) -> Void) 
{ 
    DispatchQueue.global().async 
    { 
     let instance = T.init() 
     block(instance) 
    } 
} 


createAndExecuteAsync(OtherClass.self){ $0.myProperty = 2 } 

// instead of OtherClass.createAndExecuteAsync{ $0.myProperty = 2 } 
関連する問題