2012-01-01 7 views
5

Quiero tener una longitud fija de contenido mutable compartida búfer de datos y que es ¿cómo creo que:Comportamiento de NSData initWithBytesNoCopy: longitud: freeWhenDone:

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

Qué pasaría si modifico buffer después de haber creado una NSData de eso? ¿NS Data reflejará el cambio que hice al buffer?

Puedo garantizar que sharedData no recibirá dealloc cuando quiero modificar buffer.

Esta es la forma en que realmente quiero usarlo:


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); 

Respuesta

7

El initWithBytesNoCopy: va a crear efectivamente una envoltura alrededor de la NSData búfer existente; así que sí, las cosas que acceden a través del [sharedData bytes] verán las actualizaciones que realice.

Por supuesto, no hace nada para vincular otros objetos que se crean a partir de la NSData ejemplo, por lo que por ejemplo, un [NSImage initWithData:sharedData] puede hacer una copia de la instancia NSImage, que no reflejará ningún cambio.

Además, con freeWhenDone:YES la NSData destruirá el búfer cuando se retira la última referencia, por lo que mirar hacia fuera para que =)


Por lo tanto, dado que el NSData es efectivamente una envoltura delgada alrededor de una asignación malloc() , sí, reflejará los cambios realizados en esa memoria (por cualquier proceso); pero como llamará al free() en él, es una mala idea usarlo para envolver un búfer creado de otra manera (mach_vm_allocate) con freeWhenDone:YES.

Si usted realmente no-realmente necesita usar un asignador de costumbre, creo que estaría mejor con (¿por qué?):

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.