运行时

2018-07-13  本文已影响8人  观星

运行时

- (void)noReturnNoParams {
    NSLog(@"noReturnNoParams");
}

- (NSString *)hasReturnHasParams:(NSString *)params {
    NSLog(@"hasReturnHasParams:%@",params);
    
    return params;
}

调用

// 一般调用
[self noReturnNoParams];
[self hasReturnHasParams:@"params"];

// 通过objc_msgSend调用
((void(*)(id,SEL))objc_msgSend)(self,@selector(noReturnNoParams));
((NSString *(*)(id,SEL,NSString *))objc_msgSend)(self,@selector(hasReturnHasParams:),@"this is param");

// 通过函数地址调用
void (*setter)(id,SEL);
setter = (void(*)(id, SEL, BOOL))[self methodForSelector:@selector(noReturnNoParams)];
setter(self, @selector(noReturnNoParams));

消息转发

通过 obj_msgSend 调用,在找不到imp的时候,就会进入消息转发流程

  1. 调用 + (BOOL)resolveInstanceMethod:(SEL)sel; 如果重写这个方法,动态添加未实现的方法,转发流程结束。

    + (BOOL)resolveInstanceMethod:(SEL)sel {
        NSLog(@"resolveInstanceMethod");
        
        if (sel == @selector(nofunction)) {
            
            IMP imp = imp_implementationWithBlock(^{
                NSLog(@"既然没有实现,那就动态添加方法");
            });
    
            class_addMethod([ObjcMsgSendVC class], sel, imp, "v@:");
            
              // return YES/NO不知道有什么作用,看起来没什么影响
            return NO;
        }
        
        return [super resolveInstanceMethod:sel];
    }
    
    
  2. 触发 - (id)forwardingTargetForSelector:(SEL)aSelector ;可以指定一个对象来相应这个方法,如果返回nil,则进入下一步

    - (id)forwardingTargetForSelector:(SEL)aSelector {
        NSLog(@"forwardingTargetForSelector:");
        
        if (aSelector == @selector(nofunction)) {
            // Obviously if you return self from this method, the code would just fall into an infinite loop.
            // 但是系统做了优化,返回self也没事,但是不建议这么做
            return self.delegate;
        } else {
            return [super forwardingTargetForSelector:aSelector];
        }
    }
    
  3. 正常转发,可以传递给多个对象

    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
        NSLog(@"methodSignatureForSelector:");
        
        if (aSelector == @selector(nofunction)) {
            // return nil;就不会调用下一步forwardInvocation:
            return [self methodSignatureForSelector:@selector(showWithAnimated:)];
        } else {
            return [super methodSignatureForSelector:aSelector];
        }
    }
    
    - (void)forwardInvocation:(NSInvocation *)anInvocation {
        NSLog(@"forwardInvocation:");
        
        if (anInvocation.selector == @selector(nofunction)) {
            NSLog(@"anInvocation.selector == @selector(nofunction)");
            
            [self showWithAnimated:YES];
            
        } else {
            [super forwardInvocation:anInvocation];
        }
    }
    

添加方法

SEL selector = @selector(test);
    
IMP imp =imp_implementationWithBlock(^{
    NSLog(@"这是方法实现");
});
    
Method method = class_getInstanceMethod([AddMethodVC class], selector);
    
class_addMethod([AddMethodVC class], selector, imp, method_getTypeEncoding(method));

方法交换

- (void)origin {
    NSLog(@"originMethod");
}

- (void)swizzle {
    NSLog(@"这是Swizzle方法实现");
}

- (void)swizzleMethod {
    SEL originSel = @selector(origin);
    SEL swizzleSel = @selector(swizzle);
    
    Method originMethod = class_getInstanceMethod([SwizzleMethodVC class], originSel);
    Method swizzleMethod = class_getInstanceMethod([SwizzleMethodVC class], swizzleSel);
    
    // 确定方法存在就可以直接交换,否则可以考虑,如果方法不存在,可以先添加
    BOOL didAddMethod = class_addMethod([SwizzleMethodVC class], originSel, method_getImplementation(swizzleMethod), method_getTypeEncoding(swizzleMethod));
    
    if (didAddMethod) {
        class_replaceMethod([SwizzleMethodVC class], swizzleSel, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
    } else {
        method_exchangeImplementations(originMethod, swizzleMethod);
    }
}

方法替换

- (void)replaceMethod {
    
//    Method method = class_getInstanceMethod([ReplaceMethodVC class], @selector(swizzle));
//
//    class_replaceMethod([ReplaceMethodVC class], @selector(origin), method_getImplementation(method), method_getTypeEncoding(method));
    
    Method method = class_getInstanceMethod([ReplaceMethodVC class], @selector(origin));
    
    IMP imp = imp_implementationWithBlock(^{
        NSLog(@"这是新的方法实现");
    });
    
    class_replaceMethod([ReplaceMethodVC class], @selector(origin), imp, method_getTypeEncoding(method));
}

- (void)origin {
    NSLog(@"originMethod");
}

- (void)swizzle {
    NSLog(@"这是Swizzle方法实现");
}

传送门

项目地址

上一篇下一篇

猜你喜欢

热点阅读