public
Last active

Detects object deallocations. Good for testing.

  • Download Gist
DetectDeallocations.h
Objective-C
1 2 3 4 5 6 7
// Runs given block. Returns YES if some object of class ‘c’
// was deallocated in the block. Not thread-safe.
BOOL classGetsDeallocated(Class c, void (^block)(void));
 
// Convenience interface that calls the function above.
// Releases object, returns YES if object was deallocated.
BOOL getsDeallocatedByReleasing(id object);
DetectDeallocations.m
Objective-C
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
#import <objc/runtime.h>
 
static BOOL deallocFlag = NO;
 
static void swizzle(Class c, SEL orig, SEL patch)
{
Method origMethod = class_getInstanceMethod(c, orig);
Method patchMethod = class_getInstanceMethod(c, patch);
BOOL added = class_addMethod(c, orig,
method_getImplementation(patchMethod),
method_getTypeEncoding(patchMethod));
if (added) {
class_replaceMethod(c, patch,
method_getImplementation(origMethod),
method_getTypeEncoding(origMethod));
return;
}
method_exchangeImplementations(origMethod, patchMethod);
}
 
static id swizzledDealloc(id self, SEL _cmd)
{
deallocFlag = YES;
return self;
}
 
BOOL classGetsDeallocated(Class c, void (^block)(void))
{
const SEL deallocSel = @selector(dealloc);
const SEL swizzledSel = @selector(swizzledDealloc);
class_addMethod(c, swizzledSel, (IMP) swizzledDealloc, "@@:");
swizzle(c, deallocSel, swizzledSel);
deallocFlag = NO;
block();
swizzle(c, swizzledSel, deallocSel);
return deallocFlag;
}
 
// Wouldn’t this be simply [object retainCount] == 1 for all
// cases except when somebody is doing something really stupid?
BOOL getsDeallocatedByReleasing(id object)
{
return classGetsDeallocated([object class], ^{ [object release]; });
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.