objc_msgSend
OC中的方法调用,其实都是转换为objc_msgSend函数的调用
- objc_msgSend的执行流程可以分为3大阶段
1、消息发送
2、动态方法解析
3、消息转发
objc_msgSend消息发送
image.pngobjc_msgSend 动态方法解析
image.png- (void)other
{
NSLog(@"%s", __func__);
}
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
if (sel == @selector(test)) {
// 获取其他方法
Method method = class_getInstanceMethod(self, @selector(other));
// 动态添加test方法的实现
class_addMethod(self, sel,
method_getImplementation(method),
method_getTypeEncoding(method));
// 返回YES代表有动态添加方法
return YES;
}
return [super resolveInstanceMethod:sel];
}
或者
void c_other(id self, SEL _cmd)
{
NSLog(@"c_other - %@ - %@", self, NSStringFromSelector(_cmd));
}
// 类方法的动态解析
+ (BOOL)resolveClassMethod:(SEL)sel
{
if (sel == @selector(test)) {
// 第一个参数是object_getClass(self)
class_addMethod(object_getClass(self), sel, (IMP)c_other, "v16@0:8");
return YES;
}
return [super resolveClassMethod:sel];
}
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
if (sel == @selector(test)) {
// 动态添加test方法的实现
class_addMethod(self, sel, (IMP)c_other, "v16@0:8");
// 返回YES代表有动态添加方法
return YES;
}
return [super resolveInstanceMethod:sel];
}
objc_msgSend消息转发
image.png+ (BOOL)resolveInstanceMethod:(SEL)sel
{
class_addMethod(<#Class _Nullable __unsafe_unretained cls#>, <#SEL _Nonnull name#>, <#IMP _Nonnull imp#>, <#const char * _Nullable types#>)
}
- (id)forwardingTargetForSelector:(SEL)aSelector
{
if (aSelector == @selector(test)) {
// objc_msgSend([[MJCat alloc] init], aSelector)
return [[MJCat alloc] init];
}
return [super forwardingTargetForSelector:aSelector];
}
// 方法签名:返回值类型、参数类型
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
if (aSelector == @selector(test)) {
return [NSMethodSignature signatureWithObjCTypes:"v16@0:8"];
}
return [super methodSignatureForSelector:aSelector];
}
// NSInvocation封装了一个方法调用,包括:方法调用者、方法名、方法参数
// anInvocation.target 方法调用者
// anInvocation.selector 方法名
// [anInvocation getArgument:NULL atIndex:0]
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
// anInvocation.target = [[MJCat alloc] init];
// [anInvocation invoke];
[anInvocation invokeWithTarget:[[MJCat alloc] init]];
}
可以在下面代码中尽情的变换
对象方法消息转发
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
if (aSelector == @selector(test:)) {
// return [NSMethodSignature signatureWithObjCTypes:"v20@0:8i16"];
return [NSMethodSignature signatureWithObjCTypes:"i@:i"];
// return [[[MJCat alloc] init] methodSignatureForSelector:aSelector];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
// 参数顺序:receiver、selector、other arguments
// int age;
// [anInvocation getArgument:&age atIndex:2];
// NSLog(@"%d", age + 10);
// anInvocation.target == [[MJCat alloc] init]
// anInvocation.selector == test:
// anInvocation的参数:15
// [[[MJCat alloc] init] test:15]
[anInvocation invokeWithTarget:[[MJCat alloc] init]];
int ret;
[anInvocation getReturnValue:&ret];
NSLog(@"%d", ret);
}
类方法消息转发
+ (id)forwardingTargetForSelector:(SEL)aSelector
{
// objc_msgSend([[MJCat alloc] init], @selector(test))
// [[[MJCat alloc] init] test]
if (aSelector == @selector(test)) return [[MJCat alloc] init];
return [super forwardingTargetForSelector:aSelector];
}
+ (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
if (aSelector == @selector(test)) return [NSMethodSignature signatureWithObjCTypes:"v@:"];
return [super methodSignatureForSelector:aSelector];
}
+ (void)forwardInvocation:(NSInvocation *)anInvocation
{
NSLog(@"1123");
}
@dynamic是告诉编译器不用自动生成getter和setter的实现,等到运行时再添加方法实现
应用:
通过动态解析可以做一些方法拦截
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
// 本来能调用的方法
if ([self respondsToSelector:aSelector]) {
return [super methodSignatureForSelector:aSelector];
}
// 找不到的方法
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
// 找不到的方法,都会来到这里
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
NSLog(@"找不到%@方法", NSStringFromSelector(anInvocation.selector));
}
网友评论