6

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.

Daniel G. Wilson
  • 14,955
  • 2
  • 32
  • 39
  • How are you free'ing the property? – iandotkelly Jul 30 '11 at 18:27
  • 1
    Each allocator has a paired de-allocator to *free* the allocated object. Looking at the man-page for [`malloc`](http://linux.die.net/man/3/malloc) -- but best to find the documentation related to your specific platform -- will explain what should be used ;-) –  Jul 30 '11 at 18:34
  • I tried free(property) which doesn't seem correct but I gave it a go anyway. – Daniel G. Wilson Jul 30 '11 at 18:36

2 Answers2

6

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.

Community
  • 1
  • 1
iandotkelly
  • 9,024
  • 8
  • 48
  • 67
  • That helped lead me to the answer which was actually unrelated to my use of free. Using free(self.property); was incorrect. *facepalm*. I tried free(property); which works out fine. In the future I believe I will use NSData to avoid the hassle of malloc. – Daniel G. Wilson Jul 30 '11 at 19:16
4

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.

Nathan Day
  • 5,981
  • 2
  • 24
  • 40
  • But isn't that the same problem, just now with an object instead of a raw pointer? The object must be released, the raw pointer must be freed. In both cases, the design should be thus that it is pretty clear when they can be discarded. – Rudy Velthuis Jul 30 '11 at 19:32
  • It easier to deal with an Objects because you can then stick to the retain/release rules. If you return raw bytes from a method, how do you known the caller of the method manages the memory correctly, what if the caller of the method is not interested in the returned bytes. If the bytes are returned from a private method then you can do what every you like, but if it is part of the public interface then making stuff idiot proof so you don't have to remember that method you wrote 6 months ago doesn't behave in the usually way, it much simpler to stick to a simple set of rules. – Nathan Day Jul 30 '11 at 20:08
  • That is why I wouldn't **return** memory. I would tell the caller how big it must be and then the caller can pass a buffer he or she allocated to you. You just fill the buffer. That way, ownership is much clearer, IMO. – Rudy Velthuis Jul 30 '11 at 20:35
  • Yes that is a good approach that I have often adopted a lot, but in some situation, returing the bytes of autoreleased of NSData is useful, I think some of the NSString methods do that like - [NSString UTF8String] – Nathan Day Jul 30 '11 at 20:57