介绍
这是之前《死磕Objective-C runtime运行》的重写。还是延续问答的方式,日期复用当时的日期,并加入测试代码
本文涉及测试代码在这里
问题1: 说一说objc_msgSend方法
Message: 消息, 即objc_msgSend
和objc_msgSendSuper
These functions must be cast to an appropriate function pointer type before being called
Sends a message with a simple return value to an instance of a class. When it encounters a method call, the compiler generates a call to one of the functions objc_msgSend, objc_msgSend_stret, objc_msgSendSuper, or objc_msgSendSuper_stret. Messages sent to an object’s superclass (using the super keyword) are sent using objc_msgSendSuper; other messages are sent using objc_msgSend. Methods that have data structures as return values are sent using objc_msgSendSuper_stret and objc_msgSend_stret.
这里复用上一遍文章代码
其中主要摘抄如下:
- (instancetype)init{
if(self = [super init]){
//因为PrisonCat没有覆盖class方法,所以调用self和super结果是一样的,如果把下面class注释去掉,cls = super_cls就不一样了
Class cls = [self class];
Class super_cls = [super class];
printf("place holder");
}
return self;
}
//- (Class)class{
// return objc_getClass("NSObject");
//}
Clang重写之后:
static instancetype _I_PrisonCat_init(PrisonCat * self, SEL _cmd) {
if(self = ((PrisonCat *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("PrisonCat"))}, sel_registerName("init"))){
Class cls = ((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class"));
Class super_cls = ((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("PrisonCat"))}, sel_registerName("class"));
printf("place holder");
}
return self;
}
}
从文档和转意代码来看,objective-c消息发送(方括号语法)主要靠objc_msgSend和objc_msgSendSuper来实现。
其中[self class]通过objc_msgSend
其中[super class]通过和class_getSuperclass
和objc_msgSendSuper
对于不同构架和返回函数,struct返回值用到objc_msgSend_stret
, float返回值用到objc_msgSend_fpret
或objc_msgSend_fp2ret
相应的,对于super,struct返回值用到objc_msgSendSuper
问题2: objc_msgSend失败了会怎么样
- Dynamic Method Resolution:
resolveClassMethod:
和resolveInstanceMethod
, 若返回YES同时运行时状态有新函数加入,则直接调用实现,完成消息发送 - Message Forwarding: 若不然,
forwardingTargetForSelector:
若返回不是nil和self,则完成消息发送 - Message Forwarding: 若不然,
methodSignatureForSelector:
若返回不为空,则发送消息给forwardInvocation:
由Invocation完成 - NSInvalidArgumentException : 若不然, 调用
doesNotRecognizeSelector:
抛出异常
class_addMethod测试
class_addMethod最后的参数参考文档
@interface TestClassAddMethod: NSObject
- (NSString *)hello:(NSString *)content;
@end
NSString * hello(id self, SEL selector, NSString *content){
return [NSString stringWithFormat:@"%@", content];
}
@implementation TestClassAddMethod
- (instancetype)init{
if(self = [super init]){
class_addMethod([self class], @selector(hello:), (IMP)hello, "@@:@"); //@=id :=sel
}
return self;
}
@end
假的resolveMethod测试
即使resolveInstanceMethod
返回YES, 若没有该方法,直接回调用doesNotRecognizeSelector,抛出异常
@interface TestClassFakeResolve: NSObject
- (NSString *)hello:(NSString *)content;
@end
@implementation TestClassFakeResolve
+ (BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(hello:)) {
return YES;
}
return [super resolveInstanceMethod:sel];
}
@end
正常resolveMethod测试
+ (BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(hello:)) {
class_addMethod([self class], sel, (IMP)hello, "v@:@");
return YES;
}
return [super resolveInstanceMethod:sel];
}
forwardingTargetForSelector测试
@interface TestClassForwardTarget: NSObject{
TestClassAddMethod *_surrogate;
}
- (NSString *)hello:(NSString *)content;
@end
@implementation TestClassForwardTarget
+ (BOOL)resolveInstanceMethod:(SEL)sel{
NSLog(@"resolveInstanceMethod called");
return [super resolveInstanceMethod:sel];
}
- (id)forwardingTargetForSelector:(SEL)aSelector{
if (!_surrogate) {
_surrogate = [[TestClassAddMethod alloc] init];
}
return _surrogate;
}
@end
forwardInvocation测试
@interface TestClassForwardInvocation: NSObject{
TestClassAddMethod *_surrogate;
}
- (NSString *)hello:(NSString *)content;
@end
@implementation TestClassForwardInvocation
- (id)forwardingTargetForSelector:(SEL)aSelector{
NSLog(@"forwardingTargetForSelector called");
return [super forwardingTargetForSelector:aSelector];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
NSMethodSignature* signature = [super methodSignatureForSelector:aSelector];
if (!signature) {
if (!_surrogate) {
_surrogate = [[TestClassAddMethod alloc] init];
}
signature = [_surrogate methodSignatureForSelector:aSelector];
}
return signature;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
if ([_surrogate respondsToSelector: [anInvocation selector]]){
[anInvocation invokeWithTarget:_surrogate];
}
else{
[super forwardInvocation:anInvocation];
}
}
@end
PS: 至于调用顺序,就只能用断点来查看了。
问题3: 说一说doesNotRecognizeSelector方法
doesNotRecognizeSelector
是运行时找不到对应的SEL(方法)最后调用的函数,在NSObject里实现, 虽然注释写着已经改为CF实现,但是不影响我们学习,其内部实现主要是抛出NSInvalidArgumentException
异常。这也是iOS常见的崩溃原因之一。
// Replaced by CF (throws an NSException)
- (void)doesNotRecognizeSelector:(SEL)sel {
_objc_fatal("-[%s %s]: unrecognized selector sent to instance %p",
object_getClassName(self), sel_getName(sel), self);
}