2013-07-15 12 views
5

Tôi có một khu vực malloc'd lớn mà tôi muốn bọc trong một đối tượng NSData. Một thời gian sau, tôi tạo một bản sao của đối tượng NSData đó. Tôi muốn hai đối tượng NSData sống đời sống độc lập. ARC tự chăm sóc các đối tượng NSData, nhưng tôi đang cố gắng làm rõ tuổi thọ của chứa vùng malloc'd. Dưới đây là một mã số phác thảo:Nội dung của NSData có được tham chiếu riêng biệt không?

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 

Đó là OK với tôi rằng copyWithZone không sâu sao chép các vùng malloc'd - Tôi có thể sử dụng [NSData dataWithData:] nếu tôi muốn có một bản sao sâu. Điều gì không rõ ràng với tôi (và tôi không chắc chắn làm thế nào tốt nhất để kiểm tra) là đối tượng NSData sở hữu bộ đệm malloc'd cơ bản? Nếu cả hai đều giữ một tham chiếu đến bộ đệm malloc'd (sử dụng một số hình thức đếm tham chiếu mờ) đó là tuyệt vời! Nhưng nếu bộ đệm malloc'd được giải phóng khi đối tượng data được giải phóng (như ngụ ý bởi freeWhenDone:YES), data2 sẽ gặp sự cố trên tay.

Ai đó có thể giải thích NSData trong trường hợp này là gì? Ngoài ra, ai đó có thể đề xuất một thử nghiệm dứt khoát để chứng minh cho chính mình những gì đang xảy ra?

+0

Để có thời gian tốt, hãy ghi lại địa chỉ con trỏ của dữ liệu và dữ liệu2. 'NSLog (@"% p% p ", dữ liệu, dữ liệu2);' ;-) –

+0

@MatthiasBauch: bạn có ý giống như dòng cuối cùng trong ví dụ? :-) (Tôi đã sử dụng 'printf' thay vì' NSLog') –

+0

"Nếu CÓ, đối tượng trả về sẽ sở hữu con trỏ byte và giải phóng nó trên deallocation." Điều đó nói với tôi rằng bạn nên không tin vào bộ đệm còn sống sót vượt ra ngoài cuộc đời của NSData đầu tiên. Tuy nhiên, có lẽ NSData thứ hai tăng số lượng tham chiếu của NSData đầu tiên, vì vậy NSData đầu tiên sẽ không đi poof cho đến khi NSData thứ hai thực hiện. (Trong không phải ARC bạn có thể kiểm tra số tham chiếu để kiểm tra điều này.) –

Trả lời

1

Với câu hỏi cơ bản:

là nội dung của NSData riêng tham khảo-tính?

số (Nhưng nhìn vào mã của bạn, nó sẽ không thành vấn đề. Xem dưới đây sau khi dẫn dòng này).

--- Bắt đầu Diversion ---

ARC quản lý giữ lại và phát hành trên Đối tượng C mục tiêu bằng cách gửi tương đương với các thông báo retainrelease vào các thời điểm thích hợp. "Thời gian thích hợp" được xác định tại thời gian biên dịch bằng cách kiểm tra mã. Đó là chính xác mọi thứ nó làm. Khi bạn bắt đầu tạo con trỏ cho các phần không phải đối tượng của những đối tượng đó (tức là bytes), bạn sẽ tự quản lý thời gian của mình.

@CouchDeveloper cung cấp thông tin tốt về objc_precise_lifetime. Đặt thuộc tính này trên các đối tượng dữ liệu có thể bảo vệ bạn khỏi tối ưu hóa ARC khi xử lý các con trỏ nội bộ, nhưng nó không thực sự có liên quan ở đây. Điểm của objc_precise_lifetime là cho ARC biết rằng nó không được phép phát hành một đối tượng trước khi biến tham chiếu nằm ngoài phạm vi. Vấn đề nó giải quyết như sau:

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

ARC có an optimization nói rằng nó cho phép để tiêu diệt data giữa dòng (1) và đường (2), vì bạn không bao giờ tham khảo data một lần nữa, mặc dù data là trong phạm vi. Việc thêm thuộc tính objc_precise_lifetime cấm tối ưu hóa đó. Khi bạn bắt đầu sử dụng NSData rất nhiều, thuộc tính này có thể trở nên quan trọng.

--- End Diversion ---

OK, nhưng còn tình huống của bạn thì sao?

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

Sau khi mã này đã chạy, có hai khả năng (và bạn không phải quan tâm đến phần lớn thời gian đó là sự thật, vì đây là những đối tượng bất biến):

  • datadata2 đều là con trỏ mạnh cho cùng một đối tượng NSData. Đối tượng đó sở hữu bộ nhớ malloced và sẽ giải phóng nó khi deallocated. (Đây là trường hợp gần như chắc chắn xảy ra trong trường hợp cụ thể này, nhưng đó là chi tiết triển khai.)
  • data trỏ đến một đối tượng NSData sở hữu bộ nhớ lưu trữ và sẽ giải phóng khi được deallocated. data2 điểm đến một đối tượng NSData khác nhau với bộ nhớ riêng của mình (. Mà nó sẽ giải phóng khi được deallocated)

(Có những lựa chọn khác, có lẽ NSData sử dụng một nền tảng dispatch_data hoặc một chương trình copy-on-write . nhưng tất cả các tùy chọn nên xem xét một cách hiệu quả như trên từ bên ngoài.)

trong trường hợp đầu tiên, nếu data đi ra khỏi phạm vi, nhưng data2 vẫn là xung quanh, thì việc sở hữu NSData được bảo tồn. Không vấn đề gì. Trong trường hợp thứ hai, khi data vượt quá phạm vi, nó phá hủy bộ nhớ của nó, nhưng data2 có một bản sao độc lập của nó, do đó, một lần nữa không có vấn đề.

Tôi nghĩ rằng sự nhầm lẫn của bạn đến từ suy nghĩ rằng data sở hữu bộ nhớ. Nó không. Đối tượng NSDatadata điểm để sở hữu bộ nhớ. datadata2 chỉ là con trỏ.

+0

Sự nhầm lẫn của tôi xuất phát từ việc thiếu thực tế là 'dữ liệu' và' dữ liệu2' đang thực sự trỏ đến _exactly cùng một đối tượng_, do đó (dĩ nhiên) bộ đệm có chứa giống hệt nhau. Tôi đã giả định 'copyWithZone:' sẽ trả về một đối tượng mới, nhưng nó không làm điều đó (hoặc không phải trong trường hợp này, dù sao)[email protected] chỉ đúng hướng và câu trả lời của bạn giải thích tình huống chi tiết hơn nhiều. Cảm ơn! –

Các vấn đề liên quan