2012-12-17 11 views
9

Robię trochę Interop z Mono C# do Obj-C i wpadłem na ten problem. Kod C# musi przekazać wywołanie zwrotne - które wykonuje za pomocą wskaźnika funkcji. Mogę uzyskać wskaźnik funkcji od strony Obj-C i zadzwonić i wszystko działa. Ale teraz muszę podać wskaźnik funkcji jako wywołanie zwrotne do API strony trzeciej, która działa z blokami jako wywołanie zwrotne. Chcę, aby strona trzecia zadzwoniła do funkcji C# - więc w pewien sposób próbuję przekonwertować wskaźnik funkcji na blok, aby strona trzecia mogła go uruchomić, lub utworzyć jakiś mostek - utwórz własny blok, który uruchamia wskaźnik funkcji i przekazuje go stronie trzeciej. Nie mogę znaleźć sposobu na zrobienie tego - w jaki sposób wygenerowałbym blok z informacją o tym, która funkcja ma zostać uruchomiona, a następnie przekazuje ją stronie trzeciej. Może jest inna opcja dla mnie?"Konwertowanie" wskaźnika funkcji na blok w celu-C

Edycja: Umieszczenie funkcji w zmiennej globalnej może działać, ale chcę mieć wiele takich funkcji, ponieważ interfejs API innej firmy jest asynchroniczny i nie chcę, aby wywoływał nieprawidłowe wywołanie zwrotne.

Kod Próbowałem:

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 

I wtedy uruchomić to z

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

I to nie z BAD_ACCESS. Może robię coś złego, bo nie jestem jeszcze biegły w Obj-C. Mogę potwierdzić, że wywołanie zwrotne jest w porządku, jeśli uruchomione jest bezpośrednio i że blok jest wywoływany, ale zawiedzie w linii funkcji (wyniku).

Odpowiedz

6

dlaczego nie wystarczy mieć prostą funkcję

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

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

Cóż, masz rację. Z jakiegoś powodu nie pomyślałem o tym. Działa świetnie i bardzo czysto. Dziękuję Ci! – Amitloaf

5

Co

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

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

Następnie myBlock jest blok, który przechwytuje wartość wskaźnika funkcji i wywołuje funkcję, gdy blok jest wykonywany.


DODANO: Moja propozycja, oparta na kodzie, używając @property (i zakładając, że kompilacja z 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

Zmienna globalna? To nie jest zbyt dobre, ponieważ wtedy nie mogę niektórych z nich.Próbowałem umieścić myBlock jako członka w klasie razem z myFunc, ale kiedy próbuję uruchomić myFunc z myBlock, prawdopodobnie nie jest to w jego zasięgu i kończy się niepowodzeniem z BAD_ACCESS. Sądzę, że zmienne globalne byłyby ostatecznością, ale wolałbym podejście nieglobalne. – Amitloaf

+0

@ Amitrop: Nie chciałem sugerować zmiennej globalnej. 'myFunc' może być dowolnym wskaźnikiem funkcji. Wartość jest przechwytywana w bloku, gdy blok jest przypisany. –

+0

Dodałem trochę więcej informacji o tym, jak próbowałem implementować coś takiego, jak sugerujesz. Chciałbym, aby twoje myśli o tym, jak go rozwiązać, dzięki! – Amitloaf

0

Blok jest pod maską wskaźnikiem do lokalnej struktury danych. Blok traci ważność, gdy tylko opuścisz zakres, w którym został zadeklarowany. Zakres jest instrukcją if w init; jak tylko opuścisz to, blok jest nieważny.

Łamiecie tutaj konwencje kodowania w zły sposób. Po pierwsze, zmienne instancji powinny rozpoczynać się od podkreślenia, aby wszyscy widzieli, co robisz. Lepiej używać właściwości bez deklarowania zmiennych instancji w ogóle. I każda właściwość bloku powinna być zadeklarowana jako "kopia". Jeśli to zrobisz, wszystko będzie dobrze.