Does ARC work with Core Graphics objects? - objective-c

I recently started a new project using Automatic Reference Counting (ARC).
When I assigned the contents of a CALayer:
UIView* view = ...
UIImage* image = ...
view.layer.contents = image.CGImage
I got an error
Implicit conversion of a non-Objective-C pointer type 'CGImageRef' to 'id' is disallowed with ARC
Simply casting the CGImageRef to id hides the error, but I was wondering if the ARC still functions correctly then?

You should really check out the ARC videos from WWDC 2011. They are available on the developer site and open through iTunes. Especially:
• Session 323 – Introducing Automatic Reference Counting
• Session 322 – Objective-C Advancements in Depth
Also, the ARC reference notes:
https://developer.apple.com/library/content/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html
Both the reference notes and the videos discuss Core Graphics (et al) and how they work with ARC.
Specifically, look at the section called "Managing Toll-Free Bridging"
In many Cocoa applications, you need to use Core Foundation-style objects, whether from the Core Foundation framework itself (such as
CFArrayRef or CFMutableDictionaryRef) or from frameworks that adopt
Core Foundation conventions such as Core Graphics (you might use types
like CGColorSpaceRef and CGGradientRef).
The compiler does not automatically manage the lifetimes of Core
Foundation objects; you must call CFRetain and CFRelease (or the
corresponding type-specific variants) as dictated by the Core
Foundation memory management rules (see Memory Management Programming
Guide for Core Foundation).
If you cast between Objective-C and Core Foundation-style objects, you
need to tell the compiler about the ownership semantics of the object
using either a cast (defined in objc/runtime.h) or a Core
Foundation-style macro (defined in NSObject.h): [...]
Jörg Jacobsen has a good summary overview of the bridging options as well: Managing Toll-free Bridging in an ARC’ed Environment.
__bridge_retained (n.b.: only use it when casting from object pointer to C type pointer): I (the programmer) need to reference this object
for some time in the dark world of C type pointers which is opaque to
you, ARC. So please, please do not release this object while I still
need it. I (the programmer) promise to release it myself (in the dark
world) when I’m done with it
__bridge_transfer (n.b.: only use it when casting from C type pointer to object pointer): I (the programmer) hand over to you, ARC, an
object that I own and that I am no longer interested in in the dark
world of C type pointers that is opaque to you. Whenever you, ARC, are
done with that object please release it yourself, because you know the
right time and thus save me some work not having to do it myself.
__bridge: ARC, you keep balancing out your retains and releases as I keep balancing out mine in the dark world of C type pointers which
is…. Whenever I need to hold on to an object in the dark world I will
retain it myself and release it when appropriate. I don’t need any
extra contract with you, ARC.

Despite the references pointed out by Steve, I believe the case you show above might be special. From the Transitioning to ARC Release Notes, pay attention to the section "The Compiler Handles CF Objects Returned From Cocoa Methods":
The compiler understands Objective-C methods that return Core
Foundation types follow the historical Cocoa naming conventions (see
Advanced Memory Management Programming Guide). For example, the
compiler knows that, in iOS, the CGColor returned by the CGColor
method of UIColor is not owned.
The code example they provide:
gradientLayer.colors = [NSArray arrayWithObjects:(id)[[UIColor darkGrayColor] CGColor],
(id)[[UIColor lightGrayColor] CGColor], nil];
relies on the known return of CGColors from these methods (they are missing the cast to id that I've added in the above code, which should be corrected in their documentation soon).
Because [image CGImage] follows the naming conventions, I believe the CGImage will be bridged properly here. I think that your cast to id should be all that you need here.

One popular answer to layer.contents = (id)image.CGImage question is layer.contents = obj_unretainedObject(image.CGImage).
I do =(__bridge id)image.CGImage.

Related

Is a CGContext an object?

I've been programming since 2 months (so I'm quite a new) and i'm currently learning how to draw graphics for an iphone app but i need clarification on CGContext.
To create the current context we useCGContextRef currentContext=UIGraphicsGetCurrentContext(), here if I understand well(and please correct me if I'm wrong),UIGraphicsGetCurrentContext() create the current context but we assign it to a pointer of type CGContexRef.
Is the current context a object allocated memory on the heap or is it just a type of variable on the stack? I know we use pointer to work with the same data and avoid copying big memory blocks (right ?)
but what is really a CGContext, an object, a struct or whatever?
Short answer: CGContextRef is a pointer to a CGContext, which is a struct.
A CGContext is technically a struct, but it is conceptually an object, but in C, not Objective-C. The Core frameworks are object-oriented C frameworks.
Also, #dandan78's advice is good to help find out what things are.
It's an object disguised as an opaque C pointer. If you cast it to id it will behave like any other object (it wont need explicit retaining/releasing under ARC, can be added to collections, etc). The CGContext API requires it to be cast as a CGContextRef though.
The same goes for all of the Core Foundation SomethingRef types. Some, like CFArray can be safely cast to their equivalent Cocoa type (like NSArray). In general, it isn't that useful. It made it easier for people migrate their old Carbon-based code to Cocoa back when people still used Carbon.
Worth remembering that you can do po on a CFType in the debugger.
The point of these opaque types is that you don't need to know and don't need to care. Apple could change its internals with every release and we wouldn't know (and don't need to). Usually, FooRef types are pointers to something. Right now, it's defined as:
typedef struct CGContext *CGContextRef;
But what struct CGContext looks like, we don't know. It looks like it's really a CoreFoundation (and maybe Objective-C) object since there are the usual retain/release functions:
CGContextRef CGContextRetain (CGContextRef c);
void CGContextRelease (CGContextRef c);
The usual CoreFoundation memory naming patterns apply: you don't need to release a CGContextRef unless it was returned by a function that contains the words Create or Copy.

Memory Leaks when Working with Address Book Contacts in iOS6

I'm using ARC, and my application compiles and works without crashing. However, when I run an Analyze build, I am seeing these warnings. I come from PHP and JavaScript so naturally I have no idea what to do to fix this stuff. Can anyone help me out?
ARC needs some help when dealing with Core Foundation. Try this:
NSArray *linkedPeople = (__bridge_transfer NSArray *)ABPersonCopyArrayOfAllLinkedPeople(person);
and
NSDictionary *personDictionary = (__bridge_transfer NSDictionary *)(ABMultiValueCopyValueAtIndex(addressFromPerson, 0));
__bridge_transfer tells ARC that a non-Objective-C (i.e., Core Foundation) pointer is being moved to an Objective-C pointer, and it allows ARC to take ownership of the object for memory management purposes. CF functions with the word "copy" in them produce an object reference with a +1 reference count. If you don't explicitly call CFRelease() on the object later, then it will leak. Using __bridge_transfer, however, lets ARC do this for you.
(Note: I didn't test this, but I believe those are the issues that the static analyzer is complaining about.)
Yes, you can use:
NSArray *linkedPeople = (__bridge_transfer NSArray *)ABPersonCopyArrayOfAllLinkedPeople(person);
But Apple now recommends using:
NSArray *linkedPeople = CFBridgingRelease(ABPersonCopyArrayOfAllLinkedPeople(person));
It does the same thing, but Apple recommends you use the latter.
See WWDC 2012 session 405, 37:33 into the presentation.
So! Even though you're using Automatic Reference Counting (ARC), it's still a good idea to read up on Objective-C Memory Management:
http://longweekendmobile.com/2011/09/07/objc-automatic-reference-counting-in-xcode-explained/
But, for your specific problem:
Generally, when you see a C method in the Apple frameworks that has the word Copy in it, you're taking ownership of that Core Foundation type and you need to release it. When you want to release that type, just use:
CFRelease(addressFromPerson)
That's the first issue. Your screenshot cuts off the second error so I'm only speculating, but I think you also need to release your NSDictionary *personDictionary. Similarly:
CFRelease(personDictionary)
Note that you also need to manage the memory for linkedPeople
Normally ARC will take care of memory management for you, but when working with Core Foundation types, you still need to clean up after yourself.
I would strongly recommend you check out these great resources on memory management with ARC, particularly when dealing with CF types and toll-free bridging:
http://www.joergjacobsen.com/blog/2011/10/05/managing-toll-free-bridging-in-an-arced-environment/
http://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html

Necessary to release CGGradientCreateWithColorComponents?

I have custom UIView drawing in drawRect.
I don't know the C APIs that well so I'm not sure what memory rules they require. The Objective-C rules are pretty simple and state that you release anything you own via init retain or copy but the C function CGGradientCreateWithColorComponents is not Objective-C and the Product > Analyze reports that it is a potential leak.
Is it necessary to release the results of this function, and if so, how? And in general, when it comes to these APIs, is there any easy way to know if a function is allocating memory that you need to manually release?
UPDATE: Here is the code, thanks to the information in the answers so far. I'm getting incorrect decrement error now:
CGGradientRef theGradient=[self makeGradient:YES];
//do something with theGradient in my drawing
CGGradientRelease(theGradient); // this line Analyze says incorrect decrement of object not owned by caller
And in makeGradient I have:
- (CGGradientRef)makeGradient:(BOOL)red{
CGGradientRef gradient;
//create my gradient
return gradient;
}
The general rule is that if you call function whose name contains “Create” or “Copy”, you must release the object that it returns. This is called the “Create rule”.
You created the gradient using a function that has “Create” embedded in the name. That means you're responsible for releasing the gradient. You can use CGGradientRelease or CFRelease.
You can read about the Create rule and other memory management conventions in the Memory Management Programming Guide for Core Foundation.
You can also read Quartz 2D Programming Guide: Memory Management: Object Ownership.
UPDATE
Based on your new code samples, I now see that you need to learn about another memory management convention. ;^)
Objective-C methods use a slightly different naming convention than Core Foundation functions. Instead of putting “Create” or “Copy” in the name, the convention for Objective-C methods is that the name must start with “alloc”, “new”, “copy”, or “mutableCopy” if it returns an object that the caller must release. (You can read about Objective-C memory management conventions here.)
Change the name of your method from makeGradient: to newGradient: and the analyzer will stop complaining. I tested it! :^)
With CGGradientRelease, simply.

Updating CoreFoundation PriorityQueue implementation to take advantage of ARC for iOS

I found an implementation of a priority queue that primarily uses CFBinaryHeap to work.
I'm currently using the -fno-objc-arc compiler flag to skip the usage of ARC while compiling these files. I attempted to update this code to take advantage of ARC, though I've run into a few snags of understanding.
Is there anyone here who has updated code similar to this for use with ARC?
How do you handle things like free(), and CFRelease()? Can we just get rid of them?
What do you do with the retain and release methods you create for CFBinaryHeapCallBacks?
Do you use __bride or __bridge_transfer to reference the const void * into Objective-C objects? Likewise should you use (__bridge_retained void *) or obj_unretainedPointer() to do the reverse?
ARC basically is a compiler technology that automatically inserts calls to -retain, -release, and -autorelease as needed. It does not remove the need for retains and releases, it just makes them automatic (in the process, optimizing out many that are not required, and playing other tricks to make various common patterns much more efficient than if you did it by hand).
ARC knows nothing about Core Foundation, nor about void* objects, malloc, free, or anything other than ObjC memory management.
This means that as long as you use Core Foundation objects, you should continue to use CFRelease. And if you malloc memory, you should continue to free it.
But.... what if you want to take memory that was created by Core Foundation and transfer it to Cocoa via a toll-free bridge? That's where __bridge* comes in. One of the best sources of information is the clang docs themselves. A great blog article is Everything you need to know about ARC. It includes many useful links to the definitive information.
But here's the short answer (from Transitioning to ARC)
NSString *c = (__bridge_transfer NSString*)my_cfref; // -1 on the CFRef
CFStringRef d = (__bridge_retained CFStringRef)my_id; // returned CFRef is +1
Using __bridge_transfer logically moves a CF object into Cocoa. Using __bridge_retained logically moves a Cocoa object into CF. You use these when you are really transferring ownership of the object. In the above example, you generally shouldn't continue using the my_ variables in my opinion. These are particularly useful in cases where you are returning the result out of the function. These should be used for their logical ownership functionality only. Don't use them as a way to "fake" a manual call to retain or release.
If you just want to have a temporary "bridged" pointer to the object so you can use it in CF or Cocoa without transferring it, then use __bridge. That's a no-op that says "don't do any memory management, just let me pretend for the moment that it's the other kind of object." If you do a lot of toll-free bridging, you'll wind up using __bridge quite a lot (making it seem like a small toll.... :D)
Here is a pure objective-c implementation of PriorityQueue, that supports ARC:
https://github.com/jessedc/JCPriorityQueue/tree/experimental/heap-queue
Is simple to implement non ARC lib into XCode project. Just open "Build Phases"(menu when click on your project target) -> "Compile Sources" and to files, which are not using ARC add by double click flag "-fno-objc-arc" and your're done. So simple :)

Releasing Core Foundation object references

Do I need to release a Core Foundation objects to clear up memory? And if so, how?
For example, in the code:
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef peopleArray = ABAddressBookCopyArrayOfAllPeople(addressBook);
do I need to release peopleArray? What about addressBook?
Yes, in CoreFoundation you have to release anything with Create or Copy in the name. You do this with CFRelease(). In your case, you should be releasing both the array and the address book references.
The rules for memory management in Core Foundation are similar to those in Cocoa: if the method that returns a reference contains the words "create" or "copy", you own the reference and must call CFRelease() on that reference to relinquish ownership. Otherwise, you do not own the reference and must call CFRetain to take ownership (necessarily requiring a subsequent CFRelease to relinquish that new ownership). These rules, as taken from the Memory Management Programming Guide for Core Foundation are:
If you create an object (either
directly or by making a copy of
another object—see “The Create
Rule”), you own it.
If you get an
object from somewhere else, you do
not own it. If you want to prevent it
being disposed of, you must add
yourself as an owner (using
CFRetain).
If you are an owner of an
object, you must relinquish ownership
when you have finished using it
(using CFRelease).
In your example, both the addressBook and the peopleArray must be released. Since there is no autorelease equivalent in Core Foundation, if you are returning the a reference from a method, return the array without releasing it. You should (unless you're being evil) then include "create" in the method name to indicate to the caller that they now own a reference to the returned object. In this case, CFArray is toll-free bridged to NSCFArray, an Objective-C object that inherits from NSObject. You can thus cast peopleArray to an NSArray* and autorelease that, if you need to return it from a function/method:
return [(NSArray*)peopleArray autorelease];
Note that this only works for toll-free bridged classes. My understanding is that it's rather difficult to make your own toll-free bridged classes and only the primitive (string, array, etc.) CF classes are toll-free bridged, so this approach won't work always. Finally, if you can avoid using autorelease (i.e. you can make your memory management more explicit), that's probably always a good thing.
Another small point that no-one has mentioned yet, some CF classes have a "toll-free bridge" with their NS counterpart. CFString and NSString, CFArray and NSArray are both examples. This is relevant as you can just use release with these classes.
See this other StackOverflow question for more information.
I would suggest reading Apple's guide on Core Foundation memory management for an in-depth discussion of this. They have a similar guide for general Cocoa memory management as well.
To release a CF object, you would call the CFRelease function.
For ARC you can use.
return (__bridge_transfer NSArray*)peopleArray;
"__bridge_transfer" will transfer the ownership to ARC and therefore you don't need any further release call.