将ObjC id <protocol>并将类型化的对象转换为C指针(void *)是否安全,然后将其强制转换回来?

时间:2018-06-28 08:27:19

标签: objective-c c casting metal

我正在为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,因此我将其转换为第二版本。这里有几个问题:

  1. newCommandQueue和类似函数之后,我应该保留对象然后返回它吗?
  2. 我使用mdevice = (__strong id<MTLDevice>)device;将void *转换为ObjC类型,但是这又如何:mdevice = device;?似乎编译器没有抱怨。
  3. 对于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];
}

1 个答案:

答案 0 :(得分:1)

在这两种情况下,对-retain的调用不正确。 the Create Rule之后是MTLCreateSystemDefaultDevice(),因此已经为您保留了。您需要负责一次(自动)发布以平衡原始创作,再为您执行的每个-retain负责。

与之类似,-newCommandQueue返回一个已经保留并且最终必须释放的对象。 That's true of any method starting with "new"

禁用ARC时,

__strong不执行任何操作。 mdevice = device;很好。

将Objective-C对象指针投射到void*并返回是“安全的”(丢失类型安全性除外)。我建议您使用指向不透明结构类型的指针而不是void*,以维护类型安全。例如,typedef struct MtDevice *MtDeviceRef;,其中从未定义struct MtDevice。 Apple就是这样定义自己的类型的,例如CFStringRef