Skip to content

Instantly share code, notes, and snippets.

@calebd
Last active August 29, 2015 14:00
Show Gist options
  • Save calebd/11188417 to your computer and use it in GitHub Desktop.
Save calebd/11188417 to your computer and use it in GitHub Desktop.
NSData

Why does this work? In theory, creating a mutable version of an NSData object by referencing its original bytes using -[NSMutableData dataWithBytesNoCopy:length:freeWhenDone:], and then modifying those bytes would result in the original immutable object being modified as well.

It is worth noting that calling -[NSData dataWithBytesNoCopy:length:freeWhenDone:] results in both data objects having the same byte pointer address, and that memsetting the data returned by bytes on an immutable data object will in fact update the data that it represents.

Output:

DataTest[58994:303] original data pointer location: 0x10010a630
DataTest[58994:303] original data: <4c6f7265 6d206970 73756d20 646f6c6f 72207369 7420616d 65742c20 636f6e73 65637465 74757220 61646970 69736369 6e672065 6c69742e>
DataTest[58994:303] mutable data pointer location: 0x100201a00
DataTest[58994:303] mutable data: <4c6f7265 6d206970 73756d20 646f6c6f 72207369 7420616d 65742c20 636f6e73 65637465 74757220 61646970 69736369 6e672065 6c69742e>
DataTest[58994:303] modified mutable data pointer location: 0x100201a00
DataTest[58994:303] modified mutable data: <00000000 00000000 00006d20 646f6c6f 72207369 7420616d 65742c20 636f6e73 65637465 74757220 61646970 69736369 6e672065 6c69742e>
DataTest[58994:303] original data pointer location: 0x10010a630
DataTest[58994:303] original data: <4c6f7265 6d206970 73756d20 646f6c6f 72207369 7420616d 65742c20 636f6e73 65637465 74757220 61646970 69736369 6e672065 6c69742e>
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
// Create a string
NSString *originalString = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
// Create some data
NSData *originalData = [originalString dataUsingEncoding:NSUTF8StringEncoding];
NSLog(@"original data pointer location: %p", [originalData bytes]);
NSLog(@"original data: %@", originalData);
// Create a mutable copy without copying the bytes
NSMutableData *mutableData = [NSMutableData
dataWithBytesNoCopy:(void *)[originalData bytes]
length:[originalData length]
freeWhenDone:NO];
NSLog(@"mutable data pointer location: %p", [mutableData bytes]);
NSLog(@"mutable data: %@", mutableData);
// Make sure they are the same
NSCParameterAssert([originalData isEqualToData:mutableData]);
// Modify the mutable data
[mutableData resetBytesInRange:NSMakeRange(0, 10)];
NSLog(@"modified mutable data pointer location: %p", [mutableData bytes]);
NSLog(@"modified mutable data: %@", mutableData);
// Mirror original data
NSData *newData = [originalString dataUsingEncoding:NSUTF8StringEncoding];
// Make sure they are the same
NSCParameterAssert([originalData isEqualToData:newData]);
NSLog(@"original data pointer location: %p", [originalData bytes]);
NSLog(@"original data: %@", originalData);
}
return 0;
}
@Ciechan
Copy link

Ciechan commented Apr 22, 2014

It all boils down to the -[NSConcreteMutableData initWithBytes:length:copy:deallocator:] method which is the final constructor that actually creates the instance of NSMutableData *mutableData in the code. You can check this by adding a symbolic breakpoint on the method.

As for its implementation, it seems the copy argument is simply ignored and memory is always copied via memmove :)

@soffes
Copy link

soffes commented Apr 22, 2014

Ha silly Apple. Thanks @Ciechan!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment