What is the difference between
+ (instancetype)dataWithBytes:(const void *)bytes length:(NSUInteger)length;
and
+ (instancetype)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length;
Also,
+ (instancetype)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b;
if b == YES
, will it free the bytes automatically after converted to data?
I am working on an app and almost finished it. But the last problem is it crashes with memory error when it runs on device. It only crashes when on device, but in simulator it is perfect.
"malloc: * error for object 0x17415d0c0: Invalid pointer dequeued from free list * set a breakpoint in malloc_error_break to debug";
I have been working on this issue for several days:
iOS - My app crashes with memory Error if only runs on Device
But finally I found the problem, inside my Encryption and Decryption function, I have this:
Byte *buffer = (Byte*)malloc(asciiDataLength);
After I process with buffer, I convert it to NSData
:
NSData *plainData = [NSData dataWithBytesNoCopy:buffer length:asciiDataLength freeWhenDone:YES];
This code caused my app to crash continuously, I changed it to
NSData *plainData = [NSData dataWithBytes:buffer length:asciiDataLength];
free(buffer);
Then my app never crash again.
So, I have to free the Byte by myself, ARC will not free it for me.
+ dataWithBytes:length:
:
Creates and returns a data object containing a given number of bytes copied from a given buffer.
+ dataWithBytesNoCopy:length:
:
Creates and returns a data object that holds length bytes from the buffer bytes
.
dataWithBytes
makes a copy of the buffer for the data, while the NoCopy
version does not.
Important note: in the discussion section of dataWithBytesNoCopy:length:
:
The returned object takes ownership of the bytes pointer and frees it on deallocation. Therefore, bytes
must point to a memory block allocated with malloc
.
This means that initialising with this method essentially hands ownership of the memory to the NSData
object, which will release it with free
once it is done. If you try to initialise it with memory that you didn't allocate with malloc
, your app will crash when the data object is deallocated.
dataWithBytesNoCopy
is useful for when you get the bytes in a buffer from somewhere else, and are ready to hand them over to the NSData
object, and won't use them yourself again outside of that.
If you want to initialise the data with memory you manage yourself, use + dataWithBytesNoCopy:length:freeWhenDone:
. This is useful if the buffer will be stored somewhere persistently, and not changed or released.
However, if you are not sure how to correctly manage this memory manually, it is better to use dataWithBytes
. The other methods are present for performance reasons, as avoiding copying large chunks of data can save a lot of time, but if you aren't sure how to use them, it's probably best not to — an app that doesn't crash is preferable to an app that crashes quickly.
[[NSData alloc] initWithBytes:buffer length:buflength] create a data object containing buflength bytes copied from the buffer bytes.
[NSData dataWithBytesNoCopy:buffer length:buflength] creates a data object that holds buflength bytes from the buffer bytes. The returned object takes ownership of the buffer pointer and frees it on deallocation. Therefore, buffer must point to a memory block allocated with malloc.