Reputation: 83
I would like to swizzle an object method after the object has been created.
Example:
@interface MyObj: NSObject
-(NSString*) foo;
-(NSString*) bar;
@end
@implementation MyObj
-(NSString*) foo {return @"foo";}
-(NSString*) bar {return @"bar";}
@end
void Swizzle(object, SEL source, SEL, dest);
...
MyObj* obj = [[[MyObj alloc] init] autorelease];
NSLog(@"%@", [obj foo]);
Swizzle(obj, @selector(foo), @selector(bar));
NSLog(@"%@", [obj foo]);
Output:
foo
bar
I have looked at lots of examples of swizzling before an object is created. However as you can see I want to swizzle after an object is created.
This is because I want to track objects that are going to release (like NSThread). I don't want to swizzle NSObject dealloc because that seems overkill. I would rather swizzle only the objects I am trying to track.
Upvotes: 2
Views: 1923
Reputation: 83
The solution I ended up with was to use objc_setAssociatedObject(thread, key, object, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
That way I could detect when the thread was being released and do the cleanup I needed.
Upvotes: 0
Reputation: 237100
This honestly seems like an ill-advised attempt to avoid using Instruments. If so, the correct answer is "Just use Instruments."
But to actually answer the question: You can't do this with individual objects. Methods — even instance methods — are defined per-class, not per-object. The only way to override a method on a per-object basis is to dynamically create a subclass of the object's class that overrides the method you're interested in and isa-swizzle the object so it uses the subclass's lookup table. (This is basically how KVO does its magic notifications under the hood.) Again, this is a bit of a hack and generally a lot more trouble than it is worth, so before you do this, I would really think twice (or three times) about whether this is really necessary. For almost any use case I can come up with, there's a cleaner way to accomplish the same goal that does not involve runtime voodoo.
Upvotes: 3
Reputation: 39915
You cannot swizzle an object, only a specific class. Also, the implementation for a selector is cached, and that cache might not be cleared automatically when you swizzle, which would mean the new method is not used.
I would suggest overriding (or swizzling) dealloc
in the class you want to track, and use a property to determine if your tracking code should be performed.
@property (nonatomic) BOOL shouldTrackDealloc;
@synthesize shouldTrackDealloc;
- (void)dealloc {
if(self.shouldTrackDealloc) {
NSLog(@"dealloc of %@",self);
}
...
}
If you are tracking framework classes, you won't be able to use @synthesize
, since the instance variable won't be in the right class, but you can use associated references instead.
Upvotes: 1