Memory Management of Pointer-to-Void Context Info
A number of Cocoa methods take an optional parameter typed as void*, and often called context. An id is a universal object type; void* is just a C pointer. This means that Cocoa won’t treat this value as an object. So the use of the void* type is a clue to you that Cocoa won’t do any memory management on this value.
As an example, I’ll use beginAnimations:context:. You call this on a UIView before changing one or more of its property values, such as its size, position, or opacity, to make those changes appear animated.
A better approach is to make these context objects persistent, as instance variables or globals, and manage their memory as you would any persistent pointer. A context object will thus persist even after it is no longer needed, but it won’t actually leak, provided you release it before you yourself (the managing object) go out of existence.
Here’s a complete example:
static id g_animcontext = nil;
- (void) animate {
// set up context info pointer with memory management
[g_animcontext release];
g_animcontext = [NSDictionary dictionaryWithObject: @"object" forKey: @"key"];
[g_animcontext retain];
// prepare animation
[UIView beginAnimations:@"shrinkImage" context:g_animcontext];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
[imv setAlpha: 0];
// request animation to start
[UIView commitAnimations];
}
- (void) animationDidStop:(NSString*)anim
finished:(NSNumber *)f context:(void *)c {
NSDictionary* d = c; // cast back to dictionary, use as desired
// no memory management for context info here
// ...
}
- (void)dealloc {
[g_animcontext release];
// ... other releases and so forth ...
[super dealloc];
}
Considerations of this sort do not apply to parameters that are typed as objects. For instance, when you call postNotificationName:object:userInfo:, the userInfo is typed as an NSDictionary and is retained for you (and released after the notification is posted); its memory management is not your concern.
Memory Management of C Struct Pointers
A value obtained through a C function that is a pointer to a struct (its type name will usually end in “Ref”) is a kind of object, even though it isn’t a full-fledged Cocoa Objective-C object, and it must be managed in much the same way as a Cocoa object. The rule here is that if you obtained such an object through a function whose name contains the word Create or Copy, you are responsible for releasing it. In the case of a Core Foundation object (its type name begins with CF), you’ll release it with the CFRelease function; other object creation functions are paired with their own object release functions.
An Objective-C object can be sent messages even if it is nil. But CFRelease cannot take a NULL argument. Be sure that a pointer-to-struct variable is not NULL before releasing it.
The matter is not a complicated one; it’s much simpler than memory management of Cocoa objects, and the documentation will usually give you a hint about your memory management responsibilities. As an example, here (without further explanation) is some actual code from one of my apps, strongly modeled on Apple’s own example code, in which I set up a base pattern color space (for drawing with a pattern):
- (void) addPattern: (CGContextRef) context color: (CGColorRef) incolor {
CGColorSpaceRef baseSpace;
CGColorSpaceRef patternSpace;
baseSpace = CGColorSpaceCreateDeviceRGB ();
patternSpace = CGColorSpaceCreatePattern (baseSpace);
CGContextSetFillColorSpace (context, patternSpace);
CGColorSpaceRelease (patternSpace);
CGColorSpaceRelease (baseSpace);
// ...
}
Similarly, you can retain a Core Foundation object, if you are afraid that it might go out of existence while you still need it, with the CFRetain function, and you are then, once again, responsible for releasing it with the CFRelease function.
When a Core Foundation object type is toll-free bridged with a Cocoa object type, it makes no difference whether you use Core Foundation memory management or Cocoa memory management. For example, if you obtain a CFStringRef and assign it to an NSString variable, sending release to it through the NSString variable is just as good as calling CFRelease on it.