Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C and Objective-C - Correct way to free an unsigned char pointer

in my app I create an unsigned char pointer using this function:

- (unsigned char*)getRawData
{
// First get the image into your data buffer
CGImageRef image = [self CGImage];
NSUInteger width = CGImageGetWidth(image);
NSUInteger height = CGImageGetHeight(image);

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

unsigned char *rawData = malloc(height * width * 4);
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);

CGContextSetBlendMode(context, kCGBlendModeCopy);

CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, (CGFloat)width, (CGFloat)height), image);
CGContextRelease(context);

// Now your rawData contains the image data in the RGBA8888 pixel format.

return rawData;
}

And in another class I assign a property to that pointer like so: self.bitmapData = [image getRawData];

Where in this process can I free that malloc'd memory? When I try to free the property in dealloc, it gives me an exc_bad_access error. I feel like I'm missing a fundamental c or objective-c concept here. All help is appreciated.

like image 519
Daniel G. Wilson Avatar asked Jul 30 '11 18:07

Daniel G. Wilson


2 Answers

There is a good discussion about the safety of using malloc/free in objective-c here.

As long as you correctly free() the memory that you malloc(), there should be no issue.

I personally think that using NSMutableData or NSMutableArray is just easier. If you don't need ultimate performance, I would not use the C malloc/free statements directly.

like image 115
iandotkelly Avatar answered Nov 04 '22 01:11

iandotkelly


One way around this sort of issue is to use NSMutableData, so you can replace

unsigned char *rawData = malloc(height * width * 4);

with

myData = [[NSMutableData alloc] initWithCapacity:height * width * 4];
unsigned char *rawData = myData.mutableBytes;

you can then release myData in your deallocator.

alternativly you can do

myData = [NSMutableData dataWithCapacity:height * width * 4];

This will then mean your myData is kept around the the duration of the event loop, you can of cause even change the return type of getRawData method to return NSMUtableData or NSData, and that way it can be retained by other parts of your code, the only time I return raw bytes in my code is if I know it will be available for the life of the object that returns it, that way if I need to hold onto the data I can retain the owner class.

Apple will often use the

myData = [[NSMutableData alloc] initWithCapacity:height * width * 4];
unsigned char *rawData = myData.mutableBytes;

pattern and then document that if you need the bytes beyond the current autorelease pool cycle you will then have to copy it.

like image 45
Nathan Day Avatar answered Nov 04 '22 00:11

Nathan Day