Runtime Swizzling 详解

Runtime 是OC运行时的动态库,也就是当OC代码被调用到内存的时候,才开始执行。于是我们便可以基于这个来做一些小操作了。

在讲解之前先论述一下基本知识。

  • load 的应用
load 可以说我们在日常开发中可以接触到的调用时间 最靠前的方法,在主函数运行之前, load 方法就会调用。

由于它的调用不是惰性的,且其只会在程序调用期间调用一次,最最重要的是,如果在类与分类中都实现了 load 方法,它们都会被调用,不像其它的在分类中实现的方法会被覆盖,这就使 load 方法成为了方法调剂的绝佳时机。

但是由于 load 方法的运行时间过早,所以这里可能不是一个理想的环境,因为某些类可能需要在在其它类之前加载,但是这是我们无法保证的。不过在这个时间点,所有的 framework 都已经加载到了运行时中,所以调用 framework 中的方法都是安全的。


Method 和 IMP 的分别


Method 是类似 @selector(method:) 的形式,而 IMP 则是方法实际指向的地址


需要掌握的objc runtime的方法,其他的方法可以在文档中查看https://developer.apple.com/reference/objectivec/1657527-objective_c_runtime

class_getInstanceMethod

class_getClassMethod

method_exchangeImplementations

 class_replaceMethod(<#__unsafe_unretained Class cls#>, <#SEL name#>, <#IMP imp#>, <#const char *types#>)


现在以一个例子来叙述

防止UIButton重复点击


import <UIKit/UIKit.h>

@interface UIButton (RepeatAction)

@property (nonatomic,assign) NSTimeInterval repeat_acceptEventInterval;

@property (nonatomic,assign) BOOL repeat_ignoreEvent;

@end


#import "UIButton+RepeatAction.h"
#import <objc/runtime.h>

@implementation UIButton (RepeatAction)

static const char * UIControl_acceptEventInterval = "UIControl_acceptEventInterval";
static const char * UIControl_ignoreEvent = "UIControl_ignoreEvent";

- (NSTimeInterval)repeat_acceptEventInterval {
    return [objc_getAssociatedObject(self, UIControl_acceptEventInterval) doubleValue];
}

- (void)setRepeat_acceptEventInterval:(NSTimeInterval)repeat_acceptEventInterval{
    objc_setAssociatedObject(self, UIControl_acceptEventInterval, @(repeat_acceptEventInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (BOOL)repeat_ignoreEvent {
    return [objc_getAssociatedObject(self, UIControl_ignoreEvent) boolValue];
}

- (void)setRepeat_ignoreEvent:(BOOL)repeat_ignoreEvent {
    objc_setAssociatedObject(self, UIControl_ignoreEvent, @(repeat_ignoreEvent), OBJC_ASSOCIATION_ASSIGN);
}

- (void)__repeat_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
    if (self.repeat_ignoreEvent) {
        return;
    }
    if (self.repeat_acceptEventInterval > 0) {
        self.repeat_ignoreEvent = YES;
        [self performSelector:@selector(setRepeat_ignoreEvent:) withObject:@(NO) afterDelay:self.repeat_acceptEventInterval];
    }
    [self __repeat_sendAction:action to:target forEvent:event];
}

+ (void)load {
    
    Method a = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:));
    Method b = class_getInstanceMethod(self, @selector(__repeat_sendAction:to:forEvent:));
    method_exchangeImplementations(a, b);
}

//预防UITabbarButton 报错
- (void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
    [super sendAction:action to:target forEvent:event];
}
@end


调用的时候,直接

源码:https://github.com/chenhanqingdev/UIButtonInterval


微博:Freddie被占用了



参考链接 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值