I have some question about Obj-C message.
(1) It's my main question: how to make sure a class has an implementation from its superclass before swizzling it or invoking it?
If I want to do method swizzling with a method which the target class didn't implement it, but its superclass did, how to make sure this class has the implementation from its superclass before method swizzling?
I know when a message sent to an object which did not implement it, the Obj-C runtime will first look up its inherit hierarchy to find the implementation from its superclass. If there is one, Obj-C will cache it in a different dispatch table and invoke it.
Can I do method swizzling with this cached implementation? If can, how to make sure there is an cached implementation before method swizzling or sending any message to this object? If not, how to add a real implementation to this class which will just invoke the super
's implementation before method swizzling?
For example, there is a class hierarchy like this:
@interface A : NSObject
- (void) helloWorld;
@end
@interface B : A
@end
@interface C : B
@end
@interface D : C
@end
@interface E : D
@end
and the implementation like this:
@implemenation A
- (void) helloWorld{
NSLog(@"hello world from class A");
}
@end
@implemenation B
// did not override -helloWorld
@end
@implemenation C
- (void) helloWorld{
[super helloWorld];
NSLog(@"hello world from class C");
}
@end
@implemenation D
// did not override -helloWorld
@end
@implemenation E
// did not override -helloWorld
@end
I want to just exactly exchange (not adding) the implementation of -helloWorld
with the Class D
at runtime. This trick will add an additional task to the original implementation if the swizzled method like this:
@implemenation D (AdditionalWorkForHelloWorld)
- (void) additionalWorkForHelloWorld{
[self additionalWorkForHelloWorld];
NSLog(@"hello every one!");
}
@end
So when I send a -helloWorld
message to the instance of Class D
or Class E
, the console will print the following messages:
-> hello world from class A
-> hello world from class C
-> hello every one!
Someday, after the class D
implements its -helloWorld
as following:
@implemenation D
- (void) helloWorld{
[super helloWorld];
NSLog(@"hello world from class D");
}
@end
and send a -helloWorld
message to the instance of Class D
or Class E
, the console will print the following messages:
-> hello world from class A
-> hello world from class C
-> hello world from class D
-> hello every one!
This method exchanging will make sure the additional task will be invoked whether class D
implements -helloWorld
or not.
I'v asked a question about how to make a C function to invoke an object's super
's implementation, and it seems not easy to do that. How does Obj-C achieve this cached mechanism to forward the message to super
's implementation?
(2) How dose Obj-C handle super
keyword? and where is super
?
In the Obj-C message, the first two arguments are hidden: self
and _cmd
. You can use them in an Obj-C implementation. But where is super
?
Is a super
equal to the self
's isa
pointer? How dose Obj-C handle super
keyword?
Every Obj-C message will convert to objc_msgSend()
or objc_msgSend_stret()
. So does every message sent to super
will convert to objc_msgSendSuper()
and objc_msgSendSuper_stret()
?
In the example mentioned previously, when I send a -helloWorld
message to the Class E
, and Class D
and E
don't respond it, Obj-C will send the message to Class C
's implementation. In the Class C
's implementation, it invokes its super
's implementation, but Class B
did not implement it, so forward it to Class A
.
In this case, the super
of Class C
should be Class B
, so it actually invokes Class B
's cached implementation, doesn't it? May I swizzle the Class B
's cached implementation?