问题
I just started learning this, so sorry if this has some obvious solution I still can't grasp.
I have these two classes:
@implementation Person
-(void)saySomething:(NSString*) something {
NSLog(@"%@",something);
}
-(void)yellSomething:(NSString*) something {
[self saySomething:[something uppercaseString]];
}
@end
and
@implementation ShoutingPerson : Person
-(void)saySomething:(NSString*)something {
[super yellSomething:something];
}
@end
This is causing a circular reference call because saySomething is always being called on the descendant class.
How can I make yellSomething invoke the saySomething method on Person class instead of the descendant class ?
回答1:
As Jonathan says, you really should avoid this if at all possible. It's just a bad design to need this functionality. If your base class is intended to be subclassed, its documentation should spell out which methods must be overridden and which others may be overridden. Anything else should not be overridden, to avoid problems like this.
That said, if you are in a very unusual situation where it is necessary (perhaps you're stuck working with 3rd party code that you cannot refactor), it is possible. But it's not pretty. You need to call objc_msgSendSuper or objc_msgSendSuper_stret manually, after constructing an instance of struct objc_super pointing to self and YourBaseClass.
Note that if you're coming from C++ the default behaviour there is the same - if you call SomeFunction() from your base class and it's a virtual method, the subclass's override will be executed. You would have to prefix your call to spell out the class explicitly, e.g. MyBaseClass::SomeFunction(). There's no direct equivalent for that in Objective-C - I'd say because it's just such a bad idea generally.
回答2:
You don't. This is how inheritance is supposed to work in Objective-C. Instead, you should document in your base class that the default implementation of -yellSomething: just calls -saySomething:. It then becomes a subclass responsibility not to screw up the stack trace.
If you really want to be able to change what calls what, have a third method in your base class:
-vocalizeSomething: (NSString *)what loudly: (BOOL)loudly;
It's the one to speak the words. Both -saySomething: and -yellSomething: call through to it directly rather than calling each other. Then the subclass can safely override either method to call the other, or call vocalizeSomething:loudly: without creating an infinite loop.
来源:https://stackoverflow.com/questions/13670919/objective-c-calling-self-message-on-a-base-class-is-invoking-the-descendant-m