Method exchange is dangerous because if the target class
(NSConcreteNotification) does not override the target function (dealloc), you
may exchange it's superclass dealloc method instead and may end up overriding a
method in a base class.
Use it with great care and avoid it in production code if possible.
Le 12 mars 2010 à 03:00, Gideon King a écrit :
> This is really cool...so I can replace a method without being a subclass or
> category.
>
> So I implemented an NSObject subclass with the new method, and did the method
> exchange, and my new method was called instead of the old one, but I had a
> problem - the call to the switched out method (dealloc from the
> NSConcreteNotification) didn't work. I assumed that was because the old
> implementation of dealloc was now moved to my class, so I changed the method
> switching so that it ensures that the old dealloc is replaced with the
> implementation of mydealloc, and that I have added a method to the
> NSConcreteNotification which is called mydealloc, and does the things that
> the old dealloc did.
>
> This seems to work, so I thought I'd post it here in case anyone else needs
> to replace a method in a private class, and be able to call the original
> implementation.
>
> #import <objc/runtime.h>
> #import <Cocoa/Cocoa.h>
>
> @interface MyConcreteNotification : NSObject {
> }
>
> - (void)mydealloc;
>
> @end
>
> @implementation MyConcreteNotification
>
> + (void)load {
> Method originalMethod =
> class_getInstanceMethod(NSClassFromString(@"NSConcreteNotification"),
> @selector(dealloc));
> Method replacedMethod = class_getInstanceMethod(self,
> @selector(mydealloc));
> IMP imp1 = method_getImplementation(originalMethod);
> IMP imp2 = method_getImplementation(replacedMethod);
> // Set the implementation of dealloc to mydealloc
> method_setImplementation(originalMethod, imp2);
> // Add a mydealloc method to the NSConcreteNotification with the
> implementation as per the old dealloc method
> class_addMethod(NSClassFromString(@"NSConcreteNotification"),
> @selector(mydealloc), imp1, NULL);
> }
>
> - (void)mydealloc {
> NSLog(@"My concrete notification is being deallocated");
> NSLog(@"Name: %...@\nobject: %...@\nuser Info: %...@\n", [self name],
> [self object], [self userInfo]);
>
> // Call the original method, whose implementation was exchanged with
> our own.
> // Note: this ISN'T a recursive call, because this method should have
> been called through dealloc.
> NSParameterAssert(_cmd == @selector(dealloc));
> [self mydealloc];
> }
>
> @end
>
>
> Regards.
>
> Gideon
>>
>> On iPhone and 64-bit Mac, the linker enforces internal classes more
>> strictly. NSConcreteNotification is private, so you can't link to it or
>> subclass it. You can still get the class via runtime introspection like
>> NSClassFromString(), which for debugging purposes ought to be good enough.
>> --
>> Greg Parker [email protected] Runtime Wrangler
>
>
> _______________________________________________
>
> Cocoa-dev mailing list ([email protected])
>
> Please do not post admin requests or moderator comments to the list.
> Contact the moderators at cocoa-dev-admins(at)lists.apple.com
>
> Help/Unsubscribe/Update your Subscription:
> http://lists.apple.com/mailman/options/cocoa-dev/devlists%40shadowlab.org
>
> This email sent to [email protected]
-- Jean-Daniel
_______________________________________________
Cocoa-dev mailing list ([email protected])
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com
This email sent to [email protected]