NSData的内容是否单独引用计数?

时间:2013-07-15 18:53:28

标签: ios objective-c cocoa-touch cocoa memory

我想要在NSData对象中包装一个大的malloc区域。一段时间后,我制作了该NSData对象的副本。我希望两个NSData对象能够独立生存。 ARC负责重新计算NSData对象本身,但我试图澄清包含的malloc'd区域的生命周期。这是一个代码草图:

float* cubeData = (float*)malloc(cubeDataSize);
printf("cubeData=%p\n", cubeData);
// cubeData=0x01beef00

for (...) { /* fill the cubeData array */ }

NSData* data = [NSData dataWithBytesNoCopy:cubeData length:cubeDataSize
  freeWhenDone:YES];

NSData* data2 = [data copyWithZone:nil]

printf("data.bytes=%p data2.bytes=%p\n", data.bytes, data2.bytes);
// data.bytes=0x01beef00 data2.bytes=0x01beef00

对我来说没关系,copyWithZone不会对malloc'd区域进行深层复制 - 如果我想要深层复制,我可以使用[NSData dataWithData:]。我不清楚(我不确定如何最好地测试)是哪个NSData对象拥有底层的malloc缓冲区?如果他们都持有对malloc缓冲区的引用(使用某种形式的不透明引用计数)那就太棒了!但是,如果释放data对象时释放malloc缓冲区(如freeWhenDone:YES所暗示的那样),data2将会遇到麻烦。

有人可以解释NSData在这种情况下的作用吗?或者,有人可以建议一个明确的测试来证明自己发生了什么吗?

1 个答案:

答案 0 :(得分:1)

基本问题:

  

NSData的内容是否单独引用计数?

没有。 (但是看看你的代码,它应该没关系。在这种转移后见下文。)

---开始转移---

ARC通过在适当的时间发送等效的retainrelease消息来管理Objective-C对象的保留和发布。通过代码检查在编译时确定“适当的时间”。这正是它所做的一切。当您开始创建指向这些对象的非对象片段(即bytes)的指针时,您可以自己管理生命周期。

@CouchDeveloper提供了有关objc_precise_lifetime的良好信息。在处理内部指针时,将此属性放在数据对象上可以保护您免受ARC优化,但这并不重要。 objc_precise_lifetime的要点是告诉ARC,在引用变量超出范围之前,不允许释放对象。它解决的问题看起来像这样:

NSData *data = ...;
void *stuff = data.bytes; // (1)
doSomething(stuff); // (2)

ARC有an optimization表示允许在第(1)行和第(2)行之间销毁data,因为你再也没有引用data,即使data在范围内。添加objc_precise_lifetime属性禁止优化。当你开始大量使用NSData时,这个属性就变得很重要了。

---结束转移---

好的,但你的情况呢?

float* cubeData = (float*)malloc(cubeDataSize);
NSData* data = [NSData dataWithBytesNoCopy:cubeData length:cubeDataSize freeWhenDone:YES];
NSData* data2 = [data copyWithZone:nil]

这段代码运行后,有两种可能性(你不应该关心大部分时间,因为这些是不可变对象):

  • datadata2都是指向同一NSData对象的强指针。该对象拥有malloced内存,并在释放时释放它。 (在这种特殊情况下几乎肯定会发生这种情况,但这是一个实现细节。)
  • data指向拥有malloced内存的NSData对象,并在解除分配时释放它。 data2指向具有自己内存的不同NSData对象(当 取消分配时,它将自由释放。)

(还有其他选项;也许NSData使用基础dispatch_data或写入时复制方案。但所有选项应该从外部有效地看起来如上所述。)

在第一种情况下,如果data超出范围,但data2仍然存在,则保留拥有NSData。没问题。在第二种情况下,当data超出范围时,它会破坏其内存,但data2有一个独立的副本,所以再没问题。

我认为你的困惑来自于认为data拥有记忆。它没有。 NSData指向拥有内存的data对象。 datadata2只是指针。