Ios C回调如何通过userdata指针返回Objective-C对象?
我正在使用一个第三方库,它需要在iOS程序中使用C回调。回调提供了一个Ios C回调如何通过userdata指针返回Objective-C对象?,ios,objective-c,callback,automatic-ref-counting,Ios,Objective C,Callback,Automatic Ref Counting,我正在使用一个第三方库,它需要在iOS程序中使用C回调。回调提供了一个void*userdata参数,我可以随意使用它。在这个回调中,我想创建一个NSData对象,该对象返回到调用最终调用回调的API的代码中。例如: // C callback: static void callback(int x, void* userdata) { if (userdata) { // This gives an error: // Pointer to no
void*
userdata参数,我可以随意使用它。在这个回调中,我想创建一个NSData对象,该对象返回到调用最终调用回调的API的代码中。例如:
// C callback:
static void callback(int x, void* userdata)
{
if (userdata)
{
// This gives an error:
// Pointer to non-const type 'NSData*' with no explicit ownership
NSData** p = (NSData**)userdata;
*p = [NSData init:...];
}
}
// main code:
NSData* d = ...; // sometimes valid, sometimes nil
library_api(callback, &d); // have the callback initialize or replace d
if (d)
{
[d doSomthing:...];
}
我使用的是ARC,我认为这是问题的根源。我曾想过使用结构来保存NSData*
,但ARC禁止结构或联合中的Objective-C对象。可能有一些\u bridge
的变体可能会有所帮助,但我不确定是哪个。我已经看了很多这样的问题,并阅读了苹果的文档,但我不清楚如何编写代码
理想情况下,如果在调用回调时d不是nil,则会释放其当前值,并用一个新的NSData对象替换它。换句话说,当library_api完成时,d始终保存回调创建的NSData对象,以前保存的任何值都会被正确释放
我想我可以不让Objective-C代码出现在回调中,只需要
malloc()
一个缓冲区来存储数据,然后将数据复制到主代码中的NSData对象,但我希望我可以避免这一额外步骤。可以让struct包含ObjC对象,它们必须是\uu未恢复的\u不安全的
或在.mm文件中
有几个选择:
1使用结构将ObjC对象保存在.m文件中
struct MyStruct
{
__unretained_unsafe id obj;
}
< P > 2使用结构在struct MyStruct
{
id obj; // no need to have __unretained_unsafe
}
3更改回调函数的签名并强制转换它(我以前没有尝试过)
4只需使用
-fno objc ARC
编译器标志将此文件设为非ARC即可您不能将对象所有权转移到void*
,但可以将对象所有权转移到CoreFoundation类型,如CFDataRef
或CFTypeRef
。然后,您可以根据需要自由地传递CF指针
e、 g:
在回调中:
static void callback(int x, void* userdata)
{
if (userdata)
{
CFTypeRef* cfDataPtr = userdata;
CFTypeRef cfInData = *cfDataPtr;
NSData* inData = (__bridge NSData*)cfInData;
NSLog(@"In Data: %@", inData);
NSData* outData = [[NSData alloc] init];
CFTypeRef cfOutData = (__bridge_retained CFTypeRef)outData; // Transfer ownership out of ARC.
*cfDataPtr = cfOutData;
}
}
static void callback(int x, void* userdata)
{
if (userdata)
{
CFTypeRef* cfDataPtr = userdata;
CFTypeRef cfInData = *cfDataPtr;
NSData* inData = (__bridge NSData*)cfInData;
NSLog(@"In Data: %@", inData);
NSData* outData = [[NSData alloc] init];
CFTypeRef cfOutData = (__bridge_retained CFTypeRef)outData; // Transfer ownership out of ARC.
*cfDataPtr = cfOutData;
}
}