Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Behavior of NSData initWithBytesNoCopy:length:freeWhenDone:

I want to have a fix length mutable content shared data buffer and that is how do I create it:

void *buffer = malloc(length);
// initialize buffer content
NSData *sharedData = [[NSData alloc] initWithBytesNoCopy:buffer length:length freeWhenDone:YES]

What happen if I modify buffer after I created a NSData from it? Will NSData reflect the change I did to buffer?

I can guaranty that sharedData will not get dealloc when I want to modify buffer.

This is how I actually want to use it:


void *my_alloc(CFIndex allocSize, CFOptionFlags hint, void *info) {return NULL;}
void my_dealloc(void *ptr, void *info) {
    mach_vm_deallocate(mach_task_self(), (mach_vm_address_t)ptr, (size_t)info);
}

size_t length = //some number
mach_vm_address_t buffer;
mach_vm_allocate(mach_task_self(), &buffer, length, VM_FLAGS_ANYWHERE);
// do something to buffer, for example pass to other process using mach RPC and expect other process will modify the content
CFAllocatorContext context = {0, (void *)length, NULL, NULL, NULL, my_alloc, NULL, my_dealloc, NULL};
CFAllocatorRef allocator = CFAllocatorCreate(NULL, &context);
CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)buffer, length, allocator);
like image 446
Bryan Chen Avatar asked Jan 01 '12 05:01

Bryan Chen


People also ask

What is NSMutableData?

An object representing a dynamic byte buffer in memory.

What is NSMutableData in Swift?

class NSMutableData. A dynamic byte buffer that bridges to Data ; use NSMutableData when you need reference semantics or other Foundation-specific behavior.


1 Answers

The initWithBytesNoCopy: will effectively create an NSData wrapper around the existing buffer; so yes, things accessing through [sharedData bytes] will see any updates you make.

Of course, it does nothing to link other objects which are created from the NSData instance, so for instance an [NSImage initWithData:sharedData] may make a copy for the NSImage instance, which won't reflect any changes.

Also, with freeWhenDone:YES the NSData will destroy the buffer when the last reference is removed, so look out for that =)


So, given that the NSData is effectively a thin wrapper around a malloc() allocation, yes it will reflect changes made to that memory (by any process); but as it will call free() on it, it's a bad idea to use it to wrap a buffer created another way (mach_vm_allocate) with freeWhenDone:YES.

If you don't really-really need to use a custom allocator (why?), I think you'd be better off with:

NSMutableData* sharedData = [NSMutableData dataWithCapacity:length];
// `dataWithLength:` will fully allocate and zero the buffer first, if you prefer
void* buffer = [sharedData mutableBytes];
// do something to `buffer`, mach RPC, etc.
// 3: profit.
like image 113
rvalue Avatar answered Sep 21 '22 10:09

rvalue