2012-12-17 11 views
9

Mono C#からObj-CにいくつかのInteropを実行していて、この問題が発生しました。 C#コードは関数ポインタを使用してコールバックを渡す必要があります。 私はObj-C側から関数ポインタを取得して呼び出すことができ、すべてが機能します。 しかし、私は今ブロックをコールバックとして扱う第三者APIへのコールバックとして、その関数ポインタを与える必要があります。 サードパーティがC#関数を呼び出そうとしています。つまり、関数ポインタをブロックに変換して、サードパーティがそれを実行できるようにしたり、何らかのブリッジを作成したりする方法で、自分のブロックを作成します。その関数ポインタを実行し、それを第三者に渡します。私はそれを行う方法を見つけることができないように見える - 私は実行する関数の情報を持つブロックを生成し、それを第三者に与える方法を教えてください。 私には別の選択肢がありますか?Object-Cで関数ポインタをブロックに変換する

編集:関数をグローバル変数に入れてもうまくいくかもしれませんが、サードパーティAPIが非同期であり、間違ったコールバックを呼びたくないので、それらの多数を持つことができます。

typedef void (*DummyAction)(char * result); 
typedef void (^DummyBlock)(char * result); 

@interface FunctionToBlock : NSObject 
{ 
    DummyAction function; 
    DummyBlock block; 
} 

- (id) initWithFunction: (DummyAction) func; 
- (DummyBlock) block; 
@end 

@implementation FunctionToBlock : NSObject 
- (id) initWithFunction: (DummyAction) func { 
    if (self = [super init]) { 
     function = func; 
     block = ^(char * result) { 
      function(result); 
     }; 
    } 
    return self; 
} 

- (DummyBlock) block { 
    return block; 
} 
@end 

をそして私は

void RegisterCallback(char * text, DummyAction callback) 
{ 
    FunctionToBlock *funcToBlock = [[FunctionToBlock alloc] initWithFunction : callback]; 
    funcToBlock.block(text); 
} 

でこれを実行すると、それはBAD_ACCESSで失敗します。

コードは、私が試してみました。たぶん私はObj-Cにあまり堪能ではないので、何か間違っているのかもしれません。コールバックが直接実行され、ブロックが呼び出されていても関数(結果)行で失敗した場合は、コールバックが正常であることを確認できます。

答えて

6

理由だけブロックはフードの下で、ローカルデータ構造へのポインタである

typedef void (*DummyAction)(char * result); 
typedef void (^DummyBlock)(char * result); 

DummyBlock functionToBlock(DummyAction func) { 
    return [[^(char * result) { 
       func(result); 
      } copy] autorelease]; 
} 
+1

さて、あなたは正しいです。何らかの理由で、私はそれを考えなかった。素晴らしい作品と非常にきれいな作品。ありがとうございました! – Amitloaf

5

その後

void (*myFunc)(int x); // ... your function pointer 

void (^myBlock)(int) = ^(int x) { 
    myFunc(x); 
}; 

について何myBlockは、関数ポインタの値をキャプチャし、ブロックが実行されたときに関数を呼び出すブロックです。


を追加しました:私の提案、あなたのコードに基づいて、@propertyを使って(そしてあなたはARCでコンパイルすると仮定して):

FunctionToBlock.h:

typedef void (*DummyAction)(char * result); 
typedef void (^DummyBlock)(char * result); 

@interface FunctionToBlock : NSObject 
{ 
    DummyAction function; // Not really needed. 
} 

- (id) initWithFunction: (DummyAction) func; 
@property(copy, nonatomic) DummyBlock block; // "copy" is important here! 

@end 

FunctionToBlock.m:

#import "FunctionToBlock.h" 

@implementation FunctionToBlock : NSObject 
@synthesize block = _block; // Can be ommitted if you use Xcode 4.4 or later. 

- (id) initWithFunction: (DummyAction) func 
{ 
    if (self = [super init]) { 
     function = func; // Not really needed. 
     self.block = ^(char * result) { 
      func(result); // Use "func", not "self->function", to avoid retain cycle. 
     }; 
    } 
    return self; 
} 
+0

グローバル変数?それは私がそれらのいくつかをすることはできませんので、あまり良くありません。私はmyFlockと一緒にクラスにメンバーとしてmyBlockを入れてみましたが、myFlockをmyBlockから実行しようとすると、おそらくそのスコープ内にはなく、BAD_ACCESSで失敗します。私はグローバル変数が最後の手段だと思うが、私は非グローバルなアプローチを好むだろう – Amitloaf

+0

@Amitloaf:私はグローバル変数を提案したくなかった。 'myFunc'はどの関数ポインタでもかまいません。値は、ブロックが割り当てられたときにブロック内に取り込まれます。 –

+0

あなたの提案したようなものをどのように実装しようとしたか、いくつかの情報を追加しました。それを解決する方法について、あなたの考えが欲しいです、ありがとう! – Amitloaf

0

単純な機能を持っていません。ブロックは、宣言されたスコープを離れるとすぐに無効になります。スコープはinit内のif文です。あなたがそれを残すとすぐに、ブロックは無効です。

ここではコーディング規則を壊しています。最初に、インスタンス変数はアンダースコアで始める必要があります。そうすれば誰もあなたがしていることを知ることができます。インスタンス変数を宣言せずにプロパティを使用する方が良い。また、すべてのブロックプロパティは "コピー"として宣言する必要があります。あなたがそうするならば、すべてが問題ありません。

関連する問題