我正在为Metal API(http://github.com/recp/cmtl)开发C包装程序/绑定。
我在typedef void MtDevice
这样的C标头中将Objective-C类型定义为void。然后,我将ObjC函数中分配的对象强制转换为 void * 指针。然后将其转换回ObjC以调用ObjC函数。
这是我的代码:
ARC样式:
MtDevice*
mtDeviceCreat() {
id<MTLDevice> mdevice;
mdevice = MTLCreateSystemDefaultDevice();
return (void *)CFBridgingRetain(mdevice);
}
MtCommandQueue*
mtCommandQueue(MtDevice *device) {
id<MTLDevice> mdevice;
id<MTLCommandQueue> mcmdQueue;
mdevice = (__bridge id<MTLDevice>)device;
mcmdQueue = [mdevice newCommandQueue];
return (void *)CFBridgingRetain(mcmdQueue);
}
已禁用ARC:
MtDevice*
mtDeviceCreat() {
id<MTLDevice> mdevice;
mdevice = MTLCreateSystemDefaultDevice();
return [mdevice retain];
}
MtCommandQueue*
mtCommandQueue(MtDevice *device) {
id<MTLDevice> mdevice;
id<MTLCommandQueue> mcmdQueue;
mdevice = (__strong id<MTLDevice>)device;
mcmdQueue = [mdevice newCommandQueue];
return [mcmdQueue retain];
}
我正在考虑禁用ARC,因此我将其转换为第二版本。这里有几个问题:
newCommandQueue
和类似函数之后,我应该保留对象然后返回它吗?mdevice = (__strong id<MTLDevice>)device;
将void *转换为ObjC类型,但是这又如何:mdevice = device;
?似乎编译器没有抱怨。PS:我的C函数只是用于从C调用ObjC函数的包装器。我并没有尝试访问C函数中的ObjC类成员。
编辑:
发布代码:
void
mtRelease(void *obj) {
[(id)obj release];
}
编辑2:
更新的代码(已禁用ARC):
MtDevice*
mtDeviceCreat() {
return MTLCreateSystemDefaultDevice();
}
MtCommandQueue*
mtCommandQueue(MtDevice *device) {
return [(id<MTLDevice>)device newCommandQueue];
}
答案 0 :(得分:1)
在这两种情况下,对-retain
的调用不正确。 the Create Rule之后是MTLCreateSystemDefaultDevice()
,因此已经为您保留了。您需要负责一次(自动)发布以平衡原始创作,再为您执行的每个-retain
负责。
与之类似,-newCommandQueue
返回一个已经保留并且最终必须释放的对象。 That's true of any method starting with "new"。
__strong
不执行任何操作。 mdevice = device;
很好。
将Objective-C对象指针投射到void*
并返回是“安全的”(丢失类型安全性除外)。我建议您使用指向不透明结构类型的指针而不是void*
,以维护类型安全。例如,typedef struct MtDevice *MtDeviceRef;
,其中从未定义struct MtDevice
。 Apple就是这样定义自己的类型的,例如CFStringRef
。