views:

95

answers:

2

In Objective-C, how do you rewire a class's instance method to call a method in another class?

Say a UIView class A contains another UIView class called childA. I want it so that when childA's drawRect is called, a method in class A is invoked without having to subclass childA and do the desired call in its drawRect there. How can this be achieved?

Also, how do I supply a method to childA's draw class dynamically? I know this is probably not a good practice but it would be useful for testing purposes.

+1  A: 

To answer your first question about rewiring methods:

You don't want to be doing this on general principle, since it kinda defeats the whole purpose of object-oriented design, but for testing purposes, it can be useful. As long as you're on Leopard, it's not especially difficult, either.

Take a look at the Objective-C 2.0 Runtime Reference, which contains the keys to the kingdom, as it were. Look at the functions class_getInstanceMethod, method_getImplementation, method_getTypeEncoding, and class_addMethod which, in combination, let you change the methods of a class at runtime.

If you're just swizzling one selector for another, method_exchangeImplementations is a useful shortcut.

To answer your second question about supplying a method dynamically, that's as simple as passing a SEL to a method and then calling -performSelector:withObject::

@interface MyView : NSView {
    SEL drawingSelector;
    id drawingDelegate;
}
@property SEL drawingSelector;
@property id drawingDelegate;
@end

@implementation MyView

- (void)drawRect:(NSRect)rect {
    [self.drawingDelegate performSelector:drawingSelector withObject:[NSValue valueWithRect:rect]];
}

@end
Jim Puls
A: 

For the first issue you raise, it seems like you would set up UIView A as a delegate object of childA and the other UIViews - then they could use delegate methods to call the extra drawing features you wanted in A.

Either that or have each child ask for the superview and if it is of type "A" call the method you are interested in.

Kendall Helmstetter Gelner
Thanks. I am trying to do all that without having to subclass childA. It seems like your suggestion would require that I subclass childA (which is of type UIView) and do the necessary work in there.
Boon
If you don't want to subclass, you could write a Category for your UIView that overrides drawRect and call UIView A instead (which the code would have to be able to find somehow). But I'm not sure why subclassing is not a good answer....
Kendall Helmstetter Gelner
Subclassing is fine, it's just that the purpose of this question was to find out how to do it without subclassing.
Boon