Objective-c: calling [self message] in the base class calls the descendants method

I just started to study this, so sorry if this has some obvious solution that I still can’t understand.

I have 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 causes a circular reference call because saySomething always called in the descendant class.

How can I make yellSomething call the saySomething method in the Person class instead of the descendant class?

+4
source share
2 answers

As Jonathan says, you should really avoid this, if at all possible. This is just a bad design that needs this feature. If your base class is intended for a subclass, its documentation should state which methods should be overridden and which others may be overridden. Everything else should not be redefined to avoid such problems.

However, if you are in a very unusual situation when it is necessary (you may be stuck with third-party code that cannot be reorganized), this is possible. But it is ugly. You need to call objc_msgSendSuper or objc_msgSendSuper_stret manually after creating an instance of struct objc_super , pointing to self and YourBaseClass .

Note that if you use C ++, the default behavior is the same - if you call SomeFunction() from your base class and this is a virtual method, a subclass will be redefined. You will need the prefix of your call to explicitly indicate the class, for example. MyBaseClass::SomeFunction() . There is no direct equivalent for this in Objective-C - I would say because it is just such a bad idea at all.

+6
source

No. So it is assumed that inheritance should work in Objective-C. Instead, you should document in your base class that the default implementation of -yellSomething: just calls -saySomething: Then it becomes the responsibility of the subclass so as not to spoil the stack trace.

If you really want to change what calls that, you have a third method in the base class:

-vocalizeSomething: (NSString *)what loudly: (BOOL)loudly;

This is one to speak words. Both -saySomething: and -yellSomething: access it directly, not call each other. Then the subclass can safely override any method to call another or call vocalizeSomething:loudly: without creating an infinite loop.

+10
source

All Articles