11

Mono C# から Obj-C への相互運用を行っているところ、この問題に遭遇しました。C# コードはコールバックを渡す必要があります。これは、関数ポインターを使用して行います。Obj-C 側から関数ポインターを取得して呼び出すことができ、すべてが機能します。しかし、コールバックとしてブロックを操作するサードパーティ API へのコールバックとして、その関数ポインタを渡す必要があります。サードパーティに 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 に習熟していないので、何か間違ったことをしているのかもしれません。直接実行するとコールバックが正常であること、およびブロックが呼び出されていることを確認できますが、関数 (結果) 行で失敗します。

4

3 に答える 3

7

どうですか

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;
}
于 2012-12-17T12:24:20.247 に答える
6

なぜ単純な機能を持たないのですか

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

DummyBlock functionToBlock(DummyAction func) {
    return [[^(char * result) {
                 func(result);
             } copy] autorelease];
}
于 2012-12-18T00:27:32.027 に答える
0

ブロックは内部ではローカル データ構造へのポインタです。ブロックが宣言されたスコープを離れるとすぐに、ブロックは無効になります。スコープは init 内の if ステートメントです。それを離れるとすぐに、ブロックは無効になります。

あなたはここでコーディング規約を悪い方法で破っています。まず、インスタンス変数はアンダースコアで始まる必要があります。これにより、誰もが何をしているのかがわかります。インスタンス変数をまったく宣言せずにプロパティを使用することをお勧めします。また、すべてのブロック プロパティは「コピー」として宣言する必要があります。そうすれば、すべてがうまくいきます。

于 2016-02-19T13:54:36.573 に答える