美文网首页
iOS RunTime

iOS RunTime

作者: lczalh | 来源:发表于2019-12-04 17:25 被阅读0次

    1.方法交换

    我们可以将Method Swizzling功能封装为类方法,作为NSObject的类别,这样我们后续调用也会方便些。

    NSObject+Swizzling.h

    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface NSObject (Swizzling)
    
    /**
     方法交换
    
     @param originalSelector 源方法
     @param swizzledSelector 新方法
    */
    + (void)methodSwizzlingWithOriginalSelector:(SEL)originalSelector
                            andSwizzledSelector:(SEL)swizzledSelector;
                            
    @end
    
    NS_ASSUME_NONNULL_END
    

    NSObject+Swizzling.m

    #import "NSObject+Swizzling.h"
    #import<objc/runtime.h>
    
    @implementation NSObject (Swizzling)
    
    + (void)methodSwizzlingWithOriginalSelector:(SEL)originalSelector
                            andSwizzledSelector:(SEL)swizzledSelector {
        Class class = [self class];
        //原有方法
        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        //替换原有方法的新方法
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
        //先尝试給源SEL添加IMP,这里是为了避免源SEL没有实现IMP的情况
        BOOL didAddMethod = class_addMethod(class,originalSelector,
        method_getImplementation(swizzledMethod),
        method_getTypeEncoding(swizzledMethod));
        if (didAddMethod) {//添加成功:说明源SEL没有实现IMP,将源SEL的IMP替换到交换SEL的IMP
            class_replaceMethod(class,swizzledSelector,
            method_getImplementation(originalMethod),
            method_getTypeEncoding(originalMethod));
        } else {//添加失败:说明源SEL已经有IMP,直接将两个SEL的IMP交换即可
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    }
    
    @end
    

    ViewController.m

    #import "ViewController.h"
    #import "NSObject+Swizzling.h"
    
    @implementation ViewController (Swizzling)
    
    + (void)load {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            // 交换对象方法
            [self methodSwizzlingWithOriginalSelector:@selector(viewWillAppear:) andSwizzledSelector:@selector(lczViewWillAppear:)];
            
            // 交换类方法
            [object_getClass([LibDevModel class]) methodSwizzlingWithOriginalSelector:@selector(onScanOver:) andSwizzledSelector:@selector(lczOnScanOver:)];
        });
    }
    
    

    2.消息转发

    2.1 转发对象方法

    LibDevModel+Swizzling.h

    #import <DoorMasterSDK/DoorMasterSDK.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface LibDevModel (Swizzling)
    - (void)lczTimerCancel;
    @end
    
    NS_ASSUME_NONNULL_END
    

    LibDevModel+Swizzling.m

    #import "LibDevModel+Swizzling.h"
    #import "GLGuardViewController.h"
    
    @implementation LibDevModel (Swizzling)
    
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
        // 获取 aSelector 的方法签名
        NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
        if (!signature) { // 如果无法获取
            // 判断 ViewController 是否能够响应 aSelector
            if ([ViewController instancesRespondToSelector:aSelector]) {
                // 获取 ViewController 中 aSelector 的方法签名
                signature = [ViewController instanceMethodSignatureForSelector:aSelector];
            }
        }
        return signature;
    }
    
    - (void)forwardInvocation:(NSInvocation *)anInvocation {
        if ([ViewController instancesRespondToSelector:anInvocation.selector]) {
            [anInvocation invokeWithTarget:[ViewController new]];
        }
    }
    
    

    GLGuardViewController.m

    #import "GLGuardViewController.h"
    
    
    @interface GLGuardViewController ()
    
    @end
    
    @implementation GLGuardViewController
    
    - (void)lczTimerCancel {
        NSLog(@"调用了");
    }
    

    2.2 转发类方法

    LibDevModel+Swizzling.h

    #import <DoorMasterSDK/DoorMasterSDK.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface LibDevModel (Swizzling)
    + (void)lczTimerCancel;
    @end
    
    NS_ASSUME_NONNULL_END
    

    LibDevModel+Swizzling.m

    + (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
        // 获取 aSelector 的方法签名
        NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
        if (!signature) { // 如果无法获取
            // 判断 ViewController 是否能够响应 aSelector
            if ([GLGuardViewController respondsToSelector:aSelector]) {
                // 获取 ViewController 中 aSelector 的方法签名
                signature = [GLGuardViewController methodSignatureForSelector:aSelector];
            }
        }
        return signature;
    }
    
    + (void)forwardInvocation:(NSInvocation *)anInvocation {
        if ([GLGuardViewController respondsToSelector:anInvocation.selector]) {
            [anInvocation invokeWithTarget:[GLGuardViewController class]];
        }
    }
    

    GLGuardViewController.m

    #import "GLGuardViewController.h"
    
    
    @interface GLGuardViewController ()
    
    @end
    
    @implementation GLGuardViewController
    
    + (void)lczTimerCancel {
        NSLog(@"调用了");
    }
    

    相关文章

      网友评论

          本文标题:iOS RunTime

          本文链接:https://www.haomeiwen.com/subject/mvaqgctx.html