How to release this? - iphone

I'm creating an bitmap context, and in my code there is this:
bitmapData = malloc(bitmapByteCount);
context = CGBitmapContextCreate (bitmapData,
pixelsWidth,
pixelsHeight,
8, // bits per component
bitmapBytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedFirst);
before the method returns the CGContextRef object, I think I must release the bitmapData. Can I safely call free(bitmapData) before I return the context?

The documentation for CGBitmapContextCreate says this:
In iOS 4.0 and later, and Mac OS X
v10.6 and later, you can pass NULL if
you want Quartz to allocate memory for
the bitmap. This frees you from
managing your own memory, which
reduces memory leak issues.
I would suggest you pass NULL instead of a malloc'd pointer and you will be free of worrying about its memory.
However, be mindful that CGBitmapContextCreate has 'create' in its name, so by convention you will own the object returned. You will need to release this at some point with CFRelease().

Jasarien's answer is best if you're developing for iOS version 4.0 or newer. If you want to support older versions, then keep reading.
You have to keep the bitmapData around as long as the context is being used. If you try to draw into the bitmap context and you've freed bitmapData, Bad Things will happen. The best solution is to free bitmapData after you call CFRelease on the context. If you called CGBitmapContextCreateImage to extract a CGImage from the bitmap context then don't worry... when you release the bitmap context, the CGImage will make its own copy of the bitmap data.
What this means is that making a method or function that creates and returns a bitmap context might not be the greatest idea. If you can, it would be best to create the context at the top of the method, use it in that methpd, and then release the context and free the bitmap at the end of the method. If you can't do that, consider storing the context and its bitmapData in ivars. If you need multiple bitmap contexts at one time, you'll probably want to create an object to track the context and its bitmapContext.
This is why it's best to pass NULL for the bitmapData if you're only supporting iOS version 4.0 or newer. If you're on 4.0+ and pass NULL, you can safely ignore the stuff I said above and just make sure that the caller eventually calls CFRelease on the context you return.

Related

How to access CGContext for creating CGLayer offscreen

Intention: creating CGLayer offscreen, draw some complicated stuff on it from second thread and use it later for quick drawing on main thread
Problem: CGLayerCreateWithContext(context, size, info) expects an already existing CGContext so that it knows for what kind of context it needs to be optimized.
Solution I found so far: CGContextRef ctx = UIGraphicSetCurrentContext()
but this function doesn't seem to exist anymore.
Question: Isn't there another way to access something like a default context? Or do i really need to wait for the first drawRect: call just for accessing UIGraphicsGetCurrentContext() and creating all CGLayers from main thread with one wasted drawing run?
you can create an image context by doing something like:
UIGraphicsBeginImageContext(rect);
// your drawing code
UIGraphicsEndImageContext();
with that said, i'm not sure you can do this from a thread other than main. worth a try, though.

Using CGDataProviderCreateWithData callback

I'm using CGDataProviderCreateWithData to (eventually) create a UIImage from a malloced array of bytes. I call CGDataProviderCreateWithData like this:
provider = CGDataProviderCreateWithData(NULL, dataPtr, dataLen, callbackFunc);
where
dataPtr is the previously malloced array of data bytes for the image,
dataLen is the number of bytes in the dataPtr array, and
callbackFunc is as described in the CGDataProviderCreateWithData documentation:
void callbackFunc(void *info, const void *data, size_t size);
The callback function is called when the data provider is released so I could free() dataPtr there, but I may want to continue using it (dataPtr) and at some later stage free it. This block of code will be called multiple times, and the flow will look something like:
malloc(dataPtr)
create image (call CGDataProviderCreateWithData etc)
display image
release image (and so release data provider created by CGDataProviderCreateWithData)
continue to use dataPtr
free(dataPtr)
so 1..6 may be executed multiple times. I don't want dataPtr hanging around for the entire execution of the program (and it may change in size anyway), so I want to malloc/free it as necessary.
The problem is that I can't free(dataPtr) in the callback from CGDataProviderCreateWithData because I still want to use it, so I want to free it some time later - and I can't free it until I know that the data provider no longer needs it (as far as I can tell CGDataProviderCreateWithData uses the array I pass, it doesn't take a copy).
I can't do (1) above until I know it is ok to free and re-malloc dataPtr, so what I really want to do is block waiting for the data provider to be freed (well, I want to know whether I should re-enter the 1..6 block of code, which I can't do until the data provider is freed). It will be - I create the data provider, create the image and immediately display it and release the data provider. The trouble is that the data provider isn't actually released until the UIImage is released and is finished with it.
I'm reasonably new to objective-c and iOS. Am I missing something obvious?
If you malloc the memory for the provider's data, you really want to to free it in the callback. Do not be tempted to try to circumvent this in any manner. It be too easy to leak and would be susceptible to simple memory issues.
Having said that, there are two simple solutions that address your question. Either:
Make your own copy of the data that you'll manage separately from the provider; or
Instead of using the void * renditions of the CGDataProvider methods, use the CFData rendition (e.g. CGDataProviderCreateWithCFData) and then you can maintain your own strong reference to this data object (or if in non-ARC code, do your own retain of the data object). The object will not be deallocated until all strong references are resolved (or, in non-ARC code, all of your manual retain calls are resolved with a corresponding release or autorelease call).
With either of these approaches, you can continue to let CGProviderRef manage the memory as it sees fit, but you can continue to use the data object for your own purposes, too.
I ran into a similar problem as well. I wanted to use CGImageCreateWithJPEGDataProvider, so used CGDataProviderRef with a malloc'd byte array. I was getting the same problem, when trying to free the byte array at some point after creating the Data Provider Reference.
It occurs because the data provider reference takes over the ownership of the byte array, so can only be freed by the reference, when it is done with it.
I agree with #TheBlack in that if you need the data elsewhere, make a copy of it.
What I'm doing is essentially the same to what you want to achieve, I just took different route.
This whole process is wrapped into NSOperation so you have control over scheduling memory usage.
CGImageRef imageRef = [image CGImage];
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGImageGetColorSpace(imageRef);
NSUInteger bitsPerComponent = CGImageGetBitsPerComponent(imageRef);
UInt8 *rawData = calloc((height * width * bitsPerComponent), sizeof(UInt8));
NSUInteger bytesPerRow = CGImageGetBytesPerRow(imageRef);
CGContextRef context = CGBitmapContextCreate(rawData, width, height,
bitsPerComponent, bytesPerRow, colorSpace,
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host);
if (context)
{
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
// This is the place you get access to data trough rawData. Do whatever you want with it, when done, get image with
CGImageRef newImg = CGBitmapContextCreateImage(context);
}
OR
subclass CALayer, override drawInContext and use CGBitmapContextGetData to get raw data. Don't have much experience with this though, sorry, but if you want to see instant changes
on image based on user input, I'd do it this way:
Subclass UIView and CALayer which becomes layer for view and displays image. View gets input and image data (from CGBitmapContextGetData) in layer class is manipulated based on input.
Even CATiledLayer can be used for huge images in this way. When done with image, just release UIView and replace it with new one. I'll gladly provide help if you need any, just ping here.

Unable to release a CGContextRef (context is from a CGLayer)

When you create a CGLayer like so, and then get the context...it appears to be impossible to release the CGContextRef?
Releasing the CGLayerRef itself (apparently) works fine.
You'd think you could release the CGContextRef just before releasing the CGLayer - but no? Nor can you release the CGContextRef just after releasing the CGLayer.
If you release the CGContextRef, the app crashes.
CGLayerRef aether = CGLayerCreateWithContext(
UIGraphicsGetCurrentContext(), CGSizeMake(1024,768), NULL);
CGContextRef weird = CGLayerGetContext(aether);
// paths, strokes, filling etc
// paths, strokes, filling etc
// try releasing weird here
CGLayerRelease(aether);
// or, try releasing weird here
Does anyone know what is going on here? (Note further that CGContextRelease is indeed just the same as CFRelease, with some nil checking.)
In fact should you never manually release CGContextRef? Does anyone know? Cheers.
CGContextRelease(weird); // impossible, not necessary, doesn't work???
Regarding Joel's spectacular answer below:
Is releasing the CGLayerRef correct and proper? Joel has pointed out:
"Yes, since the function you're obtaining it from has 'Create' in its signature. See: documentation/CoreFoundation/"
You do not own the context returned from CGLayerGetContext, and so should not release it*. In particular, see http://developer.apple.com/library/mac/#documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html#//apple_ref/doc/writerid/cfGetRule for information regarding 'Get' functions in Core Foundation.
*: at least, you shouldn't release it given your example code. If you retained it first (CGContextRetain(weird)), then you should have a CGContextRelease to balance it.

Quartz PDF-context based function fails (occasionally) with BAD_ACCESS

Im Getting a Frequent enough BAD_ACCESS when i call this Quartz function:
CGContextDrawPDFPage ((CGContextRef)context, (CGPDFPageRef)pageRef);
Here is how i call it:
CGContextRef context = UIGraphicsGetCurrentContext();
//translate, scale
CGPDFPageRef myPageRef = CGPDFDocumentGetPage ([PDFDocument sharedPDFDocument].documentData, pageNumber);
CGContextDrawPDFPage (context, myPageRef);//BAD_ACCESS HERE
return UIGraphicsGetImageFromCurrentImageContext();//autoreleased- saved on return
//close context
Neither variable is Nil, or have been released/auto released.
Here is the Stack trace, from the debugger:
Can anyone shed any light on this? Even some pointers on how i might investigate this better. it might not even be function specific.
I probobly should mention this function is performed on a separate thread.
Check the documentation for that returns your myPageRef and see if you have to retain it.
At the time of writing the question, UIGraphicsGetImageFromCurrentImageContext and such functions where not thread safe, this was my issue. As of iOs 4.1+ many UI function are now thread safe.

Retrieving the retain count for a CGImageRef object?

While you can release a reference to a CGImageRef object using "CGImageRelease", which, according to the SDK this "decrements the retain count of a bitmap image", is there a way to inspect the current retain count for a CGImageRef instance? [cgImageRef retainCount] isn't valid since CGImageRef isn't a valid receiver of the retainCount message.
In other words, during dealloc within a class that renders an EAGLContext, I want to make sure any outstanding references to CGImageRef objects are released but I obviously don't want to call CGImageRelease(someCGImageRef) if its retain count is already 0. I've found in practice that just checking to see if the image ref is nil isn't consistent with current retain count values.
Is it a best practice to simply set the CGImageRef instance to nil after you're done with it and you've already released it so that a check for (someCGImageRef == nil) lets you know if there is an outstanding reference to it?
Thanks
If I read the docs correctly, CGImageRelease is like CFRelease except that it handles NULL differently. That means CFGetRetainCount should work as long as cgImageRef is not NULL.
Okay, so I read the rest of your question after that. You shouldn't be calling CFGetRetainCount on an object that may already have a retainCount of 0, since by then the object is already destroyed. Instead, set it to NULL.
(NULL and nil are equivalent, but nil is for Objective-C objects. CGImageRef isn't one of those, so you should probably use NULL to avoid confusing yourself later.)