本文主要是介绍纯自己记笔记,如有错误还请大神不吝赐教,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
原文:https://mp.weixin.qq.com/s/R1a1UPxr4a--quYM7RBc1Q
iOS的方法执行转发
MyClass *myClass = [[MyClass alloc] init];
[myClass printLog];
这个方法会被动态转成 objc_msgSend(myClass,@selector(printLog));
官方将此方法的定义为
objc_msgSend(void /* id self, SEL op, ... */ )
self:消息接收者
op:消息的方法名
c:参数列表 例:v@: 其中 v表示void,@表示消息接收者self,:表示sel方法
用这张图看一下 id类型,id其实里面只包含了 指向Class的 指针isa
1.class包含
①.指向元类对象的class的指针isa 我理解就是object_getClass(class)
②.class的name
③.class的变量列表 objc_ivar_list
④.class的方法列表objc_method_list
⑤.class的方法缓存 objc_cache,这里面存的是上一次被执行的方法,以便减少遍历objc_method_list的开支
2.objc_method_list包含
①.mothod_count 方法总数
②.方法体objc_method
③.objc_method_list ,将来备用的
3.objc_method包含
①.SEL类型的方法名
②.char *方法类型
③.IMP 方法实现
所以,执行一个方法的大概逻辑
·首先被动态编译成objc_msgSend(myClass,@selector(pirntLog));
·查找myClass的isa指针,找到myClass的类对象(Class),也就是MyClass
·在MyClass的method_list中查找对应的方法
·最后在找到的方法里的IMP指针,执行实现
二、消息转发
当一个对象执行selector,但没有实现的时候 [self printTest]; 系统会给三次补救机会。我们用通俗的话讲:
第一次
这个方法找不到,我们就换个已实现的方法
+(void)resolveInstanceMethod:(SEL)sel;实例方法
+(void)resolveClassMethod:(SEL)sel;类方法
示例
// ViewController.m 中
void myMethod(id self, SEL _cmd,NSString *nub) {
NSLog(@"ifelseboyxx%@",nub);
}
+ (BOOL)resolveInstanceMethod:(SEL)sel {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
if (sel == @selector(myTestPrint:)) {
#pragma clang diagnostic pop
class_addMethod([self class],sel,(IMP)myMethod,"v@:@");
return YES;
}else {
return [super resolveInstanceMethod:sel];
}
}
第二次
如果没有方法可以替换,那我们就换个tagert
-(id)forwardingTargetForSelector:(SEL)aSelector;
示例
@interface Person : NSObject
@end
@implementation Person
- (void)myTestPrint:(NSString *)str {
NSLog(@"ifelseboyxx%@",str);
}
@end
// ViewController.m 中
- (id)forwardingTargetForSelector:(SEL)aSelector {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
if (aSelector == @selector(myTestPrint:)) {
#pragma clang diagnostic pop
return [Person new];
}else{
return [super forwardingTargetForSelector:aSelector];
}
}
第三次
第一梯队的对象没实现,我们就换其他的对象咯
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector; 该方法可以被签名广撒网
-(void)forwardInvocation:(NSInvocation *)anInvocation;实现一样方法的对象去执行
示例
@interface Person : NSObject
@end
@implementation Person
- (void)myTestPrint:(NSString *)str {
NSLog(@"ifelseboyxx%@",str);
}
@end
@interface Animal : NSObject
@end
@implementation Animal
- (void)myTestPrint:(NSString *)str {
NSLog(@"tiger%@",str);
}
@end
// ViewController.m 中
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
if (aSelector == @selector(myTestPrint:)) {
#pragma clang diagnostic pop
return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
Person *person = [Person new];
Animal *animal = [Animal new];
if ([person respondsToSelector:anInvocation.selector]) {
[anInvocation invokeWithTarget:person];
}
if ([animal respondsToSelector:anInvocation.selector]) {
[anInvocation invokeWithTarget:animal];
}
}
这篇关于纯自己记笔记,如有错误还请大神不吝赐教的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!