我正在为 Metal API (http://github.com/recp/cmtl( 开发 C 包装器/绑定。
我将 Objective-C 类型定义为 void 在 C 标头中,例如typedef void MtDevice
。然后,我将在 ObjC 函数中分配的对象转换为void*指针。然后将其转换回 ObjC 以调用 ObjC 函数。
这是我的代码:
弧形风格:
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);
}
电弧禁用:
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;
?编译器似乎没有抱怨。 - 对于 ARC 和非 ARC 中的转换,像我一样在 ObjC 类型和 C void* 之间进行转换是安全的吗?
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];
}
在这两种情况下,对-retain
的调用不正确。MTLCreateSystemDefaultDevice()
遵循创建规则,因此已为您保留该规则。您负责一个(自动(发布以平衡原始创作,加上您执行的每个-retain
一个。
同样,-newCommandQueue
返回一个已保留且最终必须释放的对象。任何以"new"开头的方法都是如此。
禁用 ARC 时,__strong
不执行任何操作。mdevice = device;
很好。
将 Objective-C 对象指针投射到void*
并返回是"安全的"(除了失去类型安全(。我建议您使用指向不透明结构类型的指针而不是void*
,以保持类型安全。例如,typedef struct MtDevice *MtDeviceRef;
,其中从未定义struct MtDevice
。这就是苹果定义自己的类型的方式,例如CFStringRef
.