2012-12-17 18 views
9

Mono C# 'dan Obj-C'ye bazı Interop yapıyorum ve bu soruna rastladım. C# kodunun, bir işlev işaretçisiyle yaptığı bir geri bildirimi iletmesi gerekir. Obj-C tarafındaki fonksiyon göstergesini bulabilirim ve her şey işe yarıyor. Ancak şimdi bu işlev işaretçisini, geri çağrı olarak bloklarla çalışan üçüncü taraf API'sine geri arama olarak vermem gerekiyor. Üçüncü tarafın C# işlevini çağırmasını istiyorum - böylece bir şekilde ya işlev göstericisini bir bloğa dönüştürmeye çalışacağım, böylece üçüncü taraf bunu çalıştırabilir ya da bir çeşit köprü oluşturabilir - kendi bloğumu oluşturabilirim Bu işlev işaretçisini çalıştırır ve üçüncü tarafa verir. Bunu yapmanın bir yolunu bulmak mümkün görünmüyor - hangi işlevin çalıştırılacağı ve daha sonra üçüncü tarafa verileceği bilgileri içeren bir blok oluşturabilirim. Belki benim için başka bir seçenek var mı?Bir işlev işaretçisini nesnel C'deki bir bloğa dönüştürme "C

Düzenleme: İşlevi bir genel değişkende koymak işe yarayabilir, ancak üçüncü taraf API'sı senkronize olmayanlar gibi çok sayıda gruba sahip olmak istiyorum ve yanlış çağrıyı geri çağırmak istemiyorum.

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 

Sonra

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

ile bu çalıştırmak Ve BAD_ACCESS başarısız:

Kod denedim. Belki de Obj-C ile yetkin olmadığım için yanlış bir şey yapıyorum. Doğrudan çalıştırılırsa ve bloğa çağrılırsa ancak işlev (sonuç) satırında başarısız olursa geri aramanın tamam olduğunu doğrulayabilirim.

cevap

6

neden sadece bir blok kaputun yerel veri yapısına bir işaretçi altında olan basit işlevi

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

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

Eh, haklısın. Bir sebepten dolayı bunu düşünmemiştim. Harika ve çok temiz çalışıyor. Teşekkür ederim! – Amitloaf

5

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

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

hakkında Sonra myBlock işlev işaretçisi değerini yakalar ve blok çalıştırıldığında işlevini çağıran bir blok nedir.


EKLENDİ: sizin koduna göre Önerim, bir @property kullanarak (ve ARC ile derlemek varsayarak):

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

Genel bir değişken mi? Bu pek iyi değil çünkü o zaman birkaç tane yapamam.MyBlock'u myFunc ile birlikte bir sınıfta bir üye olarak eklemeyi denedim ancak myFunc'i myBlock'dan çalıştırmaya çalıştığımda muhtemelen kapsamı dışında ve BAD_ACCESS ile başarısız oluyor. Küresel değişkenler son çare olurdu ama küresel olmayan bir yaklaşım tercih ediyorum – Amitloaf

+0

@Amitloaf: Küresel bir değişken önermek istemedim. 'myFunc' herhangi bir fonksiyon gösterici olabilir. Değer, blok atandığında blokta yakalanır. –

+0

Önerdiğiniz gibi bir şeyi nasıl uygulamaya çalıştığımı hakkında daha fazla bilgi ekledim. Nasıl çözüleceğine dair düşüncelerinizi istersiniz, teşekkürler! – Amitloaf

0

yok. Kapsamı bildirildiği yerde bıraktığınızda bir blok geçersiz hale gelir. Kapsam, init içindeki if ifadesidir; Bunu bıraktığınız anda, blok geçersizdir.

Kodlama kurallarını burada kötü bir şekilde kırıyorsunuz. İlk olarak, örnek değişkenler bir alt çizgi ile başlamalıdır, böylece herkes ne yaptığınızı görür. Örnek değişkenlerini bildirmeden özellikleri kullanmak daha iyidir. Ve her blok özelliği "kopya" olarak bildirilmelidir. Bunu yaparsan her şey yolunda.