2013-07-15 22 views
5

我有一个大的malloc'd区域,我想包装在一个NSData对象。一段时间后,我制作了一个NSData对象的副本。我希望两个NSData对象独立生活。 ARC负责重新计算NSData对象本身,但我试图澄清包含malloc'd区域的的生命周期。这里有一个代码草图:NSData的内容是否单独参考?

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分配区域 - 我可以使用[NSData dataWithData:]如果我想有一个深拷贝。什么是不明确的(我不知道如何最好的测试)是哪个NSData对象拥有底层malloc'd缓冲区?如果它们都持有对malloc'd缓冲区的引用(使用某种形式的不透明引用计数),那太棒了!但是,如果在释放data对象(如freeWhenDone:YES所暗示)时释放malloc'd缓冲区,那么data2就会遇到麻烦。

有人可以解释什么NSData在这种情况下呢?另外,有人可以提出一个明确的测试来证明自己是怎么回事?

+0

一段好日子记录数据和数据2的指针地址。 'NSLog(@“%p%p”,data,data2);';-) –

+0

@MatthiasBauch:你的意思就像例子中的最后一行? :-)(我用'printf'代替'NSLog') –

+0

“如果是,则返回的对象获取字节指针的所有权并在解除分配时释放它。”这对我说,你最好不要指望超越第一个NSData生命周期的缓冲区。但是,第二个NSData可能会增加第一个NSData的引用计数,因此第一个NSData不会在第二个NSData执行之前变为poof。 (在非ARC中,您可以测试引用计数来检查这一点。) –

回答

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,指出它是允许的破坏线之间data(1)和线(2),因为你永远不会再次引用data,即使data在范围内。添加objc_precise_lifetime属性禁止优化。当你开始使用NSData很多时,这个属性会变得很重要。

--- End Diversion ---

好的,但您的情况如何?

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

运行此代码后,有两种可能性(和你不应该最关心的是真实的时间,因为这些都是不可变对象):

  • datadata2都是同一个NSData对象的强指针。该对象拥有malloced内存,并在释放时释放它。 (在这种情况下,这几乎肯定会发生,但这是一个实现细节。)
  • data指向拥有malloced内存的对象,并在释放时释放它。 data2指向与它自己的存储器中的不同NSData对象(其中当被释放它会释放)

(还有其他的选择;或许NSData使用底层dispatch_data或写入时复制方案但所有的选项要切实看起来像从外面以上。)

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

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

+0

我的疑惑来自于“数据”和“数据2”实际上指向__完全相同的对象这一事实,因此(当然)所包含的缓冲区又是相同的。我曾假设'copyWithZone:'会返回一个新的对象,但它不会这样做(或者在这种情况下,无论如何)。@MatthiasBauch指出了正确的方向,你的回答更详细地解释了情况。谢谢! –

相关问题