2011/05/26

Tracing Objective-C Allocation

So, let's say you have a problem tracking down some pesky retain/autorelease issue in your code. You can use NSZombieEnabled to catch double-releases, but sometimes those happen inside somebody else's code, and it's hard to track it down.

Based on a code I've found in this blog post, I've wrote a template for subclassing somebody else's class to print out the allocation history.

Here's how it looks:

#define SYNTESIZE_TRACE(X) \
@interface Trace##X : X { \
} \
@end \
\
@implementation Trace##X\
\
- (id)retain {\
NSUInteger oldRetainCount = [super retainCount];\
id result = [super retain];\
NSUInteger newRetainCount = [super retainCount];\
NSLog(@"%@<%@> ++retainCount: %d => %d\n", [self class] , self, oldRetainCount, newRetainCount);\
NSLog(@"%@\n", [NSThread callStackSymbols] );\
return result;\
}\
\
- (void)release {\
NSUInteger oldRetainCount = [super retainCount];\
BOOL gonnaDealloc = oldRetainCount == 1;\
if (gonnaDealloc) {\
NSLog(@"%@<%@> --retainCount: 1 => 0 (gonna dealloc)\n", [self class] , self);\
NSLog(@"%@\n", [NSThread callStackSymbols] );\
}\
[super release];\
if (!gonnaDealloc) {\
NSUInteger newRetainCount = [super retainCount];\
NSLog(@"%@<%@> --retainCount: %d => %d\n", [self class] , self, oldRetainCount, newRetainCount);\
NSLog(@"%@\n", [NSThread callStackSymbols] );\
}\
}\
\
@end
view raw trace.m hosted with ❤ by GitHub


And here's how you use it (in this example, I want to track AVPlayer):


SYNTESIZE_TRACE(AVPlayer)

AVPlayer* p = [[TraceAVPlayer alloc] init];


All done. Now, while running, you'll get a record of all retainCount modifications, with their stack trace.

No comments:

Post a Comment