2017-06-24 5 views
1

この質問には、Swift closure in array becomes nil in Objective-cがあります。これはラッパークラスを使用した回避策で回答しましたが、なぜ呼び出せないのか不思議ですObjective-Cでは、idでスウィフトクロージャが渡されました。簡単な例を次に示します。Objective-Cで `id 'を使ってSwift Closureを呼び出す

のObjective-Cコード:

// In a header 
typedef void (^EmptyBlock)(); 

@interface MyClassOC : NSObject 

-(void)invoke:(id)blk; 

@end 

// In an implementation (.m) file 
@implementation MyClassOC 
-(void)invoke:(id)blk { 
    EmptyBlock emptyBlock = blk; 
    emptyBlock(); 
} 
@end 

Objective-Cのブロックを提供する問題なし:

EmptyBlock block = ^{ puts("In OC empty block..."); }; 
MyClassOC * myClassOC = [[MyClassOC alloc] init]; 
[myClassOC invoke:block]; 

しかし、invoke...でObjective-Cのコードが渡されたスイフトクロージャを呼び出すことはできません私はで終わる

let myClassOC = MyClassOC() 

let myBlock : EmptyBlock = { 
    print("In Swift EmptyBlock...") 
} 

myClassOC.invoke(myBlock) 

id経由この行に210:

EmptyBlock emptyBlock = blk; 

ここで何が起こっているすべてのアイデア?

答えて

2

スウィフトタイプがObjective-Cのidタイプの不透明オブジェクトとして表現されるため、Swift 3で導入されたのはおそらくサポートの理由です。詳細についてはObjective-Cのスウィフト値のタイプthis Apple blog postにお読みください。その中でSwiftタイプは、idの場合は_SwiftValue *として渡されます。これは不透明タイプです。

このアプローチの利点は、Swiftの値型をObjective-Cコレクションに格納できることです。ただし、Objective-C側でObjective-C互換値に変換できないという欠点があります。コードをデバッグすると、ブロックがObjective-Cブロックタイプではなく_SwiftValue *として渡されていることがわかります。

bakパラメータにEmptyBlockタイプを指定すると、コードが機能します。

HTH

+0

ありがとう、説明が理にかなっています。私は 'id'から' EmptyBock'にタイプを変更することを知っています。しかし、Objective-CでSwiftから 'id 'として渡されたブロックを呼び出す方法はありますか?たとえば、Objective-Cメソッドが 'NSArray'の一部として' id'を受け取った場合はどうでしょうか?興味深いことに、このケースでは 'EmptyBlock'はSwiftに橋渡しされたObjective-C型ですが、Swift closureはその型の変数に割り当てられていますが、Objective-CはSwift型として扱うようです。 – OmniProg

+0

'_SwiftValue'は* opaque *型であり、AFAIK Appleはラップされた内容を判断し、ラップされた値にアクセスするためのObjective-Cメソッドを提供しないことを選択しました。 Objective-C側で軽量のジェネリックスを使用して解決しなければならないNSArrayの場合* Swift 3.1コンパイラがクラッシュする(*コンパイルされたプログラムではない)ことを確認しようとする私の試みとして、 "should"です。 – CRD

1

スウィフト閉鎖やObjective-Cのブロックは同じものではありませんので。 SwiftはObjective-Cブロックタイプのメソッドを呼び出すのを見ると自動的にクロージャをObjective-Cブロックに変換しますが、そうでない場合はそれを行いません。 CRDの答えによれば、Swift 3ではSwiftの値はObjective-Cオブジェクトとして表現できるため、Objective-Cオブジェクトを期待しているにもかかわらず、Objective-Cブロックが必要なことはまだ分かりません。スウィフトクロージャは、依然として不透明なオブジェクトにブリッジすることができます。

私はスウィフトと仕事からそれを渡すために考え出した唯一の方法は、のようなものです:

myClassOC.invoke(myBlock as @convention(block)() -> Void) 
+0

https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.htmlによると、ブロッククローズ規約では、EmptyBlockがSwiftにインポートされているはずです。しかし何らかの理由で、私たちはまだ表示されているようにキャストするか、代わりに 'typealias MyEmptyBlock =(@convention(block)() - > Void)'と 'let myBlock:MyEmptyBlock = ...'を使用しなければなりません。 – OmniProg

関連する問題