I have the following method:
- (void) someMethod
{
if ([super respondsToSelector:#selector(someMethod)])
{
[super performSelector:#selector(someMethod)
withObject:nil];
}
}
someMethod does not exist on superclass. as i understand, if there is no such method, runtime will ask the next responder in chain for such method till the NSObject class. And i was sure, that if statement will return NO.
Statement return YES. After that it performs selector without crash. As result - infinite recursion.
so, i have two questions:
Why [super respondsToSelector:#selector(someMethod)] returns YES ?
Why [super performSelector:#selector(someMethod) withObject:nil] does not crash with error 'does not responds to selector' ?
I think i've missed something essential.
Please, help.
Yes, you missed something essential as you suggest. From the documentation for respondsToSelector:
You cannot test whether an object inherits a method from its superclass by sending respondsToSelector: to the object using the super keyword. This method will still be testing the object as a whole, not just the superclass’s implementation. Therefore, sending respondsToSelector: to super is equivalent to sending it to self. Instead, you must invoke the NSObject class method instancesRespondToSelector: directly on the object’s superclass, as illustrated in the following code fragment.
if( [MySuperclass instancesRespondToSelector:#selector(aMethod)] )
{
// invoke the inherited method
[super aMethod];
}
HTH
Related
This question already has answers here:
NSInvocation for Dummies?
(4 answers)
Closed 7 years ago.
I came across this code in a project, where it is using NSInvocation. I want to know what it is supposed to do, and why would we ever need that. Simple explanations would be appreciated. I am posting the code.
// Public interface
#interface CCDelegateSplitter : NSObject
- (void) addDelegate: (id) delegate;
- (void) addDelegates: (NSArray*) delegates;
#end
// Private interface
#interface CCDelegateSplitter ()
#property(strong) NSMutableSet *delegates;
#end
#implementation CCDelegateSplitter
- (id) init
{
self = [super init];
_delegates = [NSMutableSet set];
return self;
}
- (void) addDelegate: (id) delegate
{
[_delegates addObject:delegate];
}
- (void) addDelegates: (NSArray*) delegates
{
[_delegates addObjectsFromArray:delegates];
}
- (void) forwardInvocation: (NSInvocation*) invocation
{
for (id delegate in _delegates) {
[invocation invokeWithTarget:delegate];
}
}
- (NSMethodSignature*) methodSignatureForSelector: (SEL) selector
{
NSMethodSignature *our = [super methodSignatureForSelector:selector];
NSMethodSignature *delegated = [(NSObject *)[_delegates anyObject] methodSignatureForSelector:selector];
return our ? our : delegated;
}
- (BOOL) respondsToSelector: (SEL) selector
{
return [[_delegates anyObject] respondsToSelector:selector];
}
#end
I'll assume you know what an NSInvocation is (if not, it's a data structure that holds all the information needed to make a method call; think "blocks" from long before blocks were added to the language).
forwardInvocation: is one of the methods that the runtime will call if it cannot find an implementation for a method. So if you pass a -doSomething message to an object [object doSomething], it will first check whether it has a doSomething method. Then it will check its superclasses. It'll try dynamic method resolution (resolveInstanceMethod for instance). It'll look for a forwarding target (forwardingTargetForSelector:), and it'll finally, if everything else fails, it'll create an invocation (using methodSignatureForSelector: and punt to forwardInvocation:. By default, forwardInvocation: just calls doesNotRecognizeSelector: which crashes you on iOS (or terminates the current thread on OS X). But you can override it to do something else (like they have here).
methodSignatureForSelector: is necessary so that the runtime system can create an invocation out of a message. This one either returns a method signature from this object or its superclasses, or it asks one of its targets for the appropriate method signature. A selector by itself isn't enough to figure out exactly how to call a method. The system needs to ask an object how the method actually works (what types it takes and what type it returns).
The code you've posted is a multi-delegate trampoline. It will accept any selector that its targets respond to (technically it'll pick a random target and see if it responds), and it'll forward that message to all of its targets.
For a similar trampoline with some comments about usage, you may want to look at RNObserverManager.
Take a look at the link in bfitch's comment. That covers what NSInvocation is, and hints at why you would use it, but doesn't cover the why in much detail.
NSInvocation lets you do fairly advanced things like creating a proxy object that actually forwards messages to another object. With NSInvocation it's possible to take ANY message at runtime and forward it to another object.
Another example is the performSelector family of methods. There's performSelector:, performSelector:withObject:, and performSelector:withObject:withObject:. (plus variants like performSelector:withObject:afterDelay:, performSelector:onThread:, etc.) Those methods take 0, 1, or or 2 objects as parameters. If you need to invoke a method on another object that takes scalar parameters, or anything other than 0, 1 or 2 objects, you're out of luck. However you can send messages with ANY type of parameters using NSInvocation.
Note that when blocks were added to Objective-C the need for tricks like performSelector and NSInvocation become less. Blocks can reference variables from their enclosing scope, which makes them more flexible.
Parent.h (extends NSObject)
like this:
#implementation InTParent
-(id)init
{
NSLog(#"Parent init method");
if (self = [super init]) {
;
}
return self;
}
-(id)initWithName:(NSString*)name;
{
NSLog(#"Parent initWithName method");
if (self = [self init]) {
;
}
return self;
}
Son.h(extends Parent)
like this:
#implementation InTSon
-(id)init
{
NSLog(#"Son init method");
if (self = [super init]) {
;
}
return self;
}
-(id)initWithName:(NSString*)name;
{
NSLog(#"Son initWithName method");
if (self = [super initWithName:name]) {
;
}
return self;
}
I use this: IntSon *_son = [[IntSon alloc] initWithName:#"asd"];
why the output is:
Son initWithName method --> Parent initWithName method --> Son init method --> Parent init method
But in Java,it perhaps like this :
Son initWithName method --> Parent initWithName method --> Parent init method
Please help me!
To understand this behavior, you have to understand how Objective-C message dispatching works. And this is a good example to illustrate it.
At a high level, any time you call a method on any object, the Objective-C runtime looks for the implementation provided the most-derived (deepest in the class hierarchy) class. If it doesn't find it, it will go the next most-derived, and so on all they way up to NSObject. The first time it finds an implementation matching the selector (method name, roughly), it will execute that implementation. When you call super, you are specifying to send a message to the next most-derived class's implementation of that method.
So in your code, you call alloc on the InTSon class, which returns an instance of IntSon with the isa pointer set to the class object InTSon. The isa pointer is how method implementations are looked for during the process of ascending the class hierarchy.
So after you have an InTSon instance, you call initWithName: on it, and it checks the class pointed to by isa (which is InTSon for an implementation of this method. It finds it, so executes it, resulting in your first output:
"Son initWithName method"
Immediately afterward, you call the superclass implementation of that method, which looks in InTParent for its implementation of initWithName: and executes that code, resulting in your second output:
Parent initWithName method
Now here is where you see a deviation from Java - you call init on self. self, however, is a pointer to an InTSon instance. So when the runtime resolves this message, it looks first for the implementation of init in the InTSon class. Of course, it finds it, and executes the code for that method, which gives you your third output, Son init method. Next you call super, which looks up and executes the InTParent implementation of init, and gives you your final output.
To sum up, regardless of where in the class hierarchy a method is called from, if it's called on self, it will always execute the most derived implementation of that method. Hope this helps, and if you have any questions please let me know!
Your class diagram looks like this:
When you send the initWithName: message to your instance of InTSon, the system looks up the method in InTSon's method table, and finds the method that we call -[InTSon initWithName:]. That method, simplified, looks like this:
// -[InTSon initWithName:]
- (id)initWithName:(NSString *)name {
return [super initWithName:name];
}
This method does [super initWithName:name]. Because it sends the message to super, the system looks in the method table of the superclass of self's class. Your object's class is InTSon, and its superclass is InTParent. So when -[InTSon initWithName:] does [super initWithName:name], the system looks for the method in InTParent's method table. It finds the method that we call -[InTParent initWithName:]. That method, simplified, looks like this:
// -[InTParent initWithName:]
- (id)initWithName:(NSString *)name {
return [self init];
}
This method does [self init]. Because it sends the message to self, the system looks in the method table for self's class. Even though we are in -[InTParent initWithName:], self is still an instance of the InTSon class. So the system looks for an init method in InTSon's method table. It finds the method we call -[InTSon init]. That method, simplified, looks like this:
// -[InTSon init]
- (id)init {
return [super initWithName:#"sdas"];
}
This method does [super initWithName:], so the system looks in the superclass's (InTParent's) method table and finds the -[InTParent initWithName:] method. And as we have just seen, -[InTParent initWithName:] ends up calling [InTSon init]. So we get infinite recursion and the app crashes.
To solve this problem, you need to pick one of InTParent's init methods as its designated initializer. You should read about designated initializers in Apple's documentation.
You should pick the initWithName: method as InTParent's designated initializer. This method must not send any init message to self. It should only send super's designated initializer message (which in the case of NSObject is the init message), and it should send it to super. So you need to write the -[InTParent initWithName:] method like this:
- (id)initWithName:(NSString *)name {
// init is NSObject's designated initializer, and we send it to super.
if ((self = [super init])) {
// your initialization code here
}
return self;
}
By picking a designated initializer, and making your designated initializer only send the superclass's designated initializer message to super, you prevent the infinite recursion.
Because "self" is a "InTSon", so [self init] calls the "InTSon" init method.
I am trying to swizzle the canPerformAction:withSender: method for UIResponder and all its subclasses which have overridden this method.
I am doing this by storing the original implementations in a dictionary keyed by class name; and looking up the dictionary in the swizzled version of the implementation before calling out to the original implementation.
This seems to work fine for some cases, but fails when the original implementation calls out to super. Then my swizzled method continuously keeps getting invoked and the program gets into infinite recursion.
What could be wrong here?
After the swizzle the -original with -custom:
-(void)custom {
[self custom]; // calls -original
}
-(void)original {
[self original]; // calls -custom
}
Said that, if you have the methods swizzled in the superclass, objc_msgSendSuper will do the same: call original for custom and versa giving you the recursion.
-(void)custom {
[self original]; // calls -custom, makes recursion
}
-(void)original {
[self custom]; // calls -original, makes recursion
}
I want' to implement "Fix and continue functionality" that was in Xcode 3.
CONTEXT:
The main idea is:
When I need to "Fix something fast", I'm not re-compiling, project. I'm compiling small Attacker class with 'updated' method implementation, loading it into memory and replacing VictimClass's method which have incorrect implementation in runtime.
I think that this method will work faster that full project recompilation.
When i'm done with fixes i'm just copying source of Attacker class method to Victim class.
PROBLEM
At the moment, I don't know how correctly call [super ...] in Attacker class.
For example, i have VictimClass
#interface VictimClass : UIView #end
#implementation VictimClass
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
}
#end
#interface AttackerClass : NSObject #end
#implementation AttackerClass
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
[self setupPrettyBackground];
}
#end
....
// EXCHANGE IMPLEMENTATIONS
Method m = class_getInstanceMethod([AttackerClass class], #selector(drawRect:));
const char * types = method_getTypeEncoding(m);
IMP attackerImp = method_getImplementation(m);
class_replaceMethod([VictimClass class], #selector(drawRect:), attackerImp, types);
// Invoking drawRect on Victim
VictimClass * view = /* */;
[view setNeedsDisplay];
At this point , when drawRect: method will be called, this will lead to exception, since drawRect: will be called on NSObject class, but not on UIView class
So, my question is, how correctly call [super drawRect:] in AttackerClass, to have possibility to correctly exchange implementation in runtime?
Main idea is to provide a way to correctly replace any method in Victim class by Attacker's class method. Generally, you don't know, superclass of Victim class.
UPDATE: Replacing implementation code added.
You will have to
get the receivers class (e.g. with object_getClass(rcv))
then get the super class of it (with class_getSuperclass(class))
then get the implementation of it (with class_getMethodImplementation(superclass, sel))
then call the imp.
done
Stop at any step if you got nil or NULL.
Oh, and all this seems silly. But I assume that the question just lacks of context to see the motivation for such a hack.
[Update]
An explanation for future readers:
The super keyword is resolved at compile time. Therefore it does not the intended thing when changing methods at runtime. A method which is intended to be injected in some object (and its class hierarchy) at runtime has to do super calls via runtime as outlined above.
Assuming that the runtime changes you're making involve modifying the superclass, you'll have to do something like this:
#implementation AttackerClass
-(void) drawRect:(CGRect)rect
{
if( [super respondsToSelector:#selector(drawRect:)] )
{
[super drawRect:rect];
}
[self setupPrettyBackground];
}
#end
This will check if the superclass "knows about" drawRect:, and doesn't call it in the case that super has no drawRect: selector.
Hence, when the superclass is NSObject the drawRect: message will not be sent. When you change it to UIView at runtime (whatever your reason for that is), the message can safely be sent.
One approach is to use objc_msgSendSuper. Your method -[AttackerClass drawRect:] will have the following implementation:
- (void)drawRect:(CGRect)rect {
struct objc_super superTarget;
superTarget.receiver = self;
superTarget.class = object_getClass(self);
objc_msgSendSuper(&superTarget, #selector(drawRect:), rect);
[self setupPrettyBackground];
}
but why do you need to call draw rect method for superclass NSObject, when NSObject hasn't got that method? just don't do it... call it just in VictimClass drawrect
I have a small question on what super means in xcode. For instance I have the following code. Would it work if i said [super dealloc] first in the dealloc method? Or should super always come last? What exactly is super - I know its the super class but is it the parent class or?
This is the .h file for this class
#interface TwitterTableViewController : PullRefreshTableViewController<TweetDelegate>
This is some code from the .m class for the above interface
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)dealloc
{
[self.twitterManager release];
[tweets release];
[lastRefreshedLabel release];
[super dealloc];
}
I have checked all over and dont have a satisfactory knowledge yet. If anyone can explain this in laymans terms would be best. thanks
super calls the implementation of the super-class. In your case this would be PullRefreshTableViewController.
Regarding if you should call super before/after your own code, it really depends on what you want to achieve by overriding the method.
In case of dealloc have a look at this question, as Nick Bull mentioned.
The super class can be regarded as a "parent class", yes, if you mean. [super dealloc] calls the implementation of the dealloc method of the super/parent class of the current object (or class, if you call it from a class method).
But, there's no such rule that "super must always come last". The reason why dealloc must always come last is that it destroys the object, so if you accessed your object after it returned, that would crash.
In addition to the existing answers here, the info in this answer may help you in deciding when to call "super".
The methods that are called when the child object/view/viewcontroller is created/initialized, the first thing you do is call the super (i.e., if you want to call it).
When the child object/view/viewcontroller is destroyed/removed, you call the super at the end of the method.
eg:
// methods called when the you are loading/showing with the view controller
-(void)viewDidLoad {
[super viewDidLoad];
//call super and then all your code goes here
}
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
//call super and then all your code goes here
}
// methods called when the you are done with the view controller
- (void)viewWillDisappear:(BOOL)animated{
//all your code goes here and then call super
[super viewWillDisappear:animated];
}
- (void)viewDidUnload {
//all your code goes here and then call super
[super viewDidUnload];
}
Similarly, for -dealloc, the super is called at the end, for -init super is called at the beginning.
Hope this demystifies Super.
super stands for the super object / aka the father of the class you are impementing which extends
in your case is a PullRefreshTableViewController
this kind of behavior is the base of all the object oriented languages, like obj-c.
in the case you are analyzing the super class has a method called
-(UITableviewStyle *) initWithStyle:style
super specifies that the messages should be sent to the parent class (superclass) of the current class. Since you're inheriting from PullRefreshTableViewController, that's where they'll get sent.
super is the parent class, here PullRefreshTableViewController. Calling [super dealloc], which you should always do if you need to implement your own dealloc method, allows your parent class (and its parent class, and so on) to clean up after themselves. It's usually a good idea to perform your own releases, and only then let the parent class do the same, because you can never be sure what the parent class will sweep away from under your feet.