2013-07-15 47 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指出了正確的方向,你的回答更詳細地解釋了情況。謝謝! –

相關問題