objc_msgSend
实现源码是汇编 为了效率
方法查找是用C++ 找到IMP 填充到当前对象里 然后 就返回到汇编
[person personTest];
objc_msgSend(person,@selector(personTest))
消息接受者(receiver): person
消息名称: personTest
- objc_msgSend的执行流程可以分为3大阶段
- 消息发送
- 动态方法解析
- 消息转发
最后如果找不到会报错:unrecognized selector sent to instance
消息发送阶段
消息发送.png
动态方法解析 阶段
平时开发的时候用不到 主要就是面试
#import "YZPerson3.h"
#import <objc/runtime.h>
@implementation YZPerson3
struct method_t {
SEL sel ;
char * types;
IMP imp;
};
-(void)retryOther{
NSLog(@"retryOther %s", __func__);
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
if(sel == @selector(persontest)){
//获取其他方法
// struct method_t * method = (struct method_t *)class_getInstanceMethod(self, @selector(retryOther));
Method method = class_getInstanceMethod(self, @selector(retryOther));
//动态添加方法
// class_addMethod(self, sel, method->imp, method-> types);
class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
}
return YES;
}
@end
YZPerson3 * person = [[YZPerson3 alloc]init];
//必须在h文件写上名字
[person persontest];
c语言方式.png动态方法解析 流程.png
image.png
消息转发 阶段
消息转发 阶段.png代码示例
- 这里是对象方法 如果要用到 类方法类似+test 需要用 + forwordInvocation:方法
@interface YZPerson4 : NSObject
-(void)test:(int)age;
@end
#import <objc/runtime.h>
@implementation YZPerson4
//这里有对应的+方法 因为底层是用receiver 直接调用的名字
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
if (aSelector == @selector(test:)) {
return [NSMethodSignature signatureWithObjCTypes:"v@:i"];
}
return [super methodSignatureForSelector:aSelector];
}
//这里有对应的+方法 因为底层是用receiver 直接调用的名字
- (void)forwardInvocation:(NSInvocation *)anInvocation{
//参数顺序 receiver selector other arguments
int age ;
[anInvocation getArgument:&age atIndex:2];
NSLog(@"age + 10 = %d",age + 10);
}
@end
NSInvocation 对象
- NSInvocation 文件里有关于方法签名的 枚举
enum _NSObjCValueType {
NSObjCNoType = 0,
NSObjCVoidType = 'v',
NSObjCCharType = 'c',
NSObjCShortType = 's',
NSObjCLongType = 'l',
NSObjCLonglongType = 'q',
NSObjCFloatType = 'f',
NSObjCDoubleType = 'd',
NSObjCBoolType = 'B',
NSObjCSelectorType = ':',
NSObjCObjectType = '@',
NSObjCStructType = '{',
NSObjCPointerType = '^',
NSObjCStringType = '*',
NSObjCArrayType = '[',
NSObjCUnionType = '(',
NSObjCBitfield = 'b'
} API_DEPRECATED("Not supported", macos(10.0,10.5), ios(2.0,2.0), watchos(2.0,2.0), tvos(9.0,9.0));
@dynamic
- 告诉编译器不用自动生成getter 和setter 的实现,等到运行时再添加方法实现
- 了解下算了
网友评论