2012-12-17 5 views
9

Sto facendo un po 'di interoperabilità da Mono C# a Obj-C e ho riscontrato questo problema. Il codice C# deve passare un callback - cosa che fa con un puntatore a funzione. Posso ottenere il puntatore di funzione dal lato Obj-C e chiamarlo e tutto funziona. Ma ora devo assegnare quel puntatore a funzione come callback all'API di terze parti che funziona con i blocchi come callback. Voglio che la terza parte chiami la funzione C# - quindi in un certo modo sto cercando di convertire il puntatore della funzione in un blocco in modo che la terza parte possa eseguirlo, o creare una specie di bridge - creare il mio blocco che esegue quel puntatore di funzione e lo consegna a terzi. Non riesco a trovare un modo per farlo - come potrei generare un blocco con informazioni su quale funzione eseguire e poi darla a terzi. Forse c'è un'altra opzione per me?"Conversione" di un puntatore di funzione su un blocco nell'obiettivo-C

Modifica: l'inserimento della funzione in una variabile globale potrebbe funzionare ma desidero essere in grado di avere una moltitudine di quelli in quanto l'API di terze parti è asincrona e non desidero che richiami la richiamata errata.

Codice ho provato:

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 

E poi ho gestito questo con

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

E non riesce con BAD_ACCESS. Forse sto facendo qualcosa di sbagliato in quanto non sono ancora molto abile con Obj-C. Posso confermare che il callback è ok se eseguito direttamente e che il blocco viene chiamato ma fallisce sulla riga della funzione (risultato).

risposta

6

perché non solo hanno una semplice funzione

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

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

Beh, hai ragione. Per qualche ragione non ci ho pensato. Funziona benissimo e molto pulito. Grazie! – Amitloaf

5

cosa circa

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

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

Poi myBlock è un blocco che cattura il valore del puntatore funzione e chiama la funzione quando viene eseguito il blocco.


AGGIUNTO: Il mio suggerimento, in base al codice, utilizzando un @property (e supponendo che si compila con 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

Una variabile globale? Non è molto buono perché non ne posso avere molti.Ho provato a mettere myBlock come membro in una classe insieme a myFunc ma quando provo a eseguire myFunc da myBlock probabilmente non è nel suo ambito e fallisce con BAD_ACCESS. Immagino che le variabili globali sarebbero l'ultima risorsa, ma preferirei un approccio non globale – Amitloaf

+0

@Amitloaf: non volevo suggerire una variabile globale. 'myFunc' può essere qualsiasi puntatore a funzione. Il valore viene catturato nel blocco quando viene assegnato il blocco. –

+0

Ho aggiunto ulteriori informazioni su come ho provato a implementare qualcosa di simile a quello che hai suggerito. Vorrebbero i tuoi pensieri su come risolverlo, grazie! – Amitloaf

0

Un blocco è sotto il cofano un puntatore a una struttura dati locale. Un blocco diventa non valido non appena si lascia l'ambito in cui è stato dichiarato. L'ambito è l'istruzione if all'interno di init; non appena lo lasci, il blocco non è valido.

Si stanno interrompendo le convenzioni di codifica in questo modo. Innanzitutto, le variabili di istanza dovrebbero iniziare con un carattere di sottolineatura, in modo che tutti possano vedere ciò che stai facendo. Meglio usare le proprietà senza dichiarare le variabili di istanza. E ogni proprietà del blocco dovrebbe essere dichiarata come "copia". Se lo fai, va tutto bene.

Problemi correlati