I'm trying to do the following:
This is my attempt:
@implementation ClassB
- (void)dealloc
{
NSLog(@"\n%@ | %@", self, NSStringFromSelector(_cmd));
}
@end
@implementation ClassC
- (void)swizzleMe:(id)target
{
SEL originalDeallocSelector = NSSelectorFromString(@"dealloc");
__block IMP callerDealloc = [target methodForSelector:originalDeallocSelector];
const char *deallocMethodTypeEncoding = method_getTypeEncoding(class_getInstanceMethod([target class], originalDeallocSelector));
IMP newCallerDealloc = imp_implementationWithBlock(^(id _caller) {
NSLog(@"\n new dealloc | calling block %p for %@", callerDealloc, _caller);
callerDealloc(_caller, originalDeallocSelector);
});
NSLog(@"\nswapping %p for %p", newCallerDealloc, callerDealloc);
class_replaceMethod([target class],
originalDeallocSelector,
newCallerDealloc,
deallocMethodTypeEncoding);
}
@end
To be used like so:
ClassB *b = [[ClassB alloc] init];
ClassC *c = [[ClassC alloc] init];
[c swizzleMe:b];
But the results are:
zombie objects disabled:
2013-07-03 13:24:58.368 runtimeTest[38626:11303]
swapping 0x96df020 for 0x2840
2013-07-03 13:24:58.369 runtimeTest[38626:11303]
new dealloc | calling block 0x2840 for <ClassB: 0x93282f0>
2013-07-03 13:24:58.370 runtimeTest[38626:11303]
<ClassB: 0x93282f0> | dealloc
2013-07-03 13:24:58.370 runtimeTest[38626:11303]
new dealloc | calling block 0x2840 for <ClassB: 0x93282f0>
2013-07-03 13:24:58.371 runtimeTest[38626:11303]
<ClassB: 0x93282f0> | dealloc
runtimeTest(38626,0xac55f2c0) malloc: *** error for object 0x93282f0: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
2013-07-03 13:24:58.371 runtimeTest[38626:11303]
new dealloc | calling block 0x2840 for <ClassB: 0x93282f0>
2013-07-03 13:24:58.372 runtimeTest[38626:11303]
<ClassB: 0x93282f0> | dealloc
zombie objects enabled (Line 11 is a EXC_BAD_ACCESS in the picture)
2013-07-03 13:34:37.466 runtimeTest[38723:11303]
swapping 0x97df020 for 0x2840
2013-07-03 13:34:37.467 runtimeTest[38723:11303]
new dealloc | calling block 0x2840 for <ClassB: 0x715a920>
2013-07-03 13:34:37.468 runtimeTest[38723:11303]
<ClassB: 0x715a920> | dealloc
Any thoughts on what am I doing wrong?
If you really want to know when an object is deallocated, then use associated objects.
Specifically, associate an object with the object you want to observe such that the object being observed has the only strong reference -- the only retain'd reference -- to the object. Then, you can override dealloc
and know that when it is called the object being observed has been (or is just about to be) deallocated.
Do not mess with the object being deallocated, though!! It will already have had all of its dealloc
methods invoked (by inheritance) and, thus, the internal state will be completely undefined.
Note that if your goal is to try and clean up something in the system frameworks, then... don't. Down that path is nothing instability and pain.
like I mentioned in the comments to nielsbot, I am NOT trying to know when an object is deallocated.
It would be helpful to know exactly what is in your injected dealloc
implementation. On the face of it, the only reason I can think of that couldn't be solved through the use of associated objects to detect deallocation is exactly because you are trying to change the behavior of a class's dealloc
, which is a really bad thing to do.
After some time I finally found the real cause of the problem: I was overlooking the signature of the IMP type. From Apple's Objective-C Runtime Reference:
IMP A pointer to the start of a method implementation.
id (*IMP)(id, SEL, ...)
Particularly, IMP has a return type of id and so in ARCLandia ARC tries to manage this id, causing the objc_retain
crash. So, assuming you have an IMP to -dealloc
, explicitly casting it to a C function pointer with return type void
makes it where ARC won't try to manage the return value anymore:
void (*deallocImp)(id, SEL) = (void(*)(id, SEL))_originalDeallocIMP;
deallocImp(self,NSSelectorFromString(@"dealloc"));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With