原文: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:参数列表 例:[email protected]: 其中 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,"[email protected]:@");

        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:"[email protected]:@"];

}

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];

}

}




相关文章:

  • 2021-10-12
  • 2021-06-14
  • 2021-10-23
  • 2021-11-06
  • 2022-12-23
  • 2021-08-13
  • 2021-10-20
  • 2021-08-05
猜你喜欢
  • 2021-10-26
  • 2021-07-22
  • 2021-07-12
  • 2021-08-10
  • 2022-03-04
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案