Runtime Swizzling 详解

来源:互联网 发布:做淘宝代销店铺没人买 编辑:程序博客网 时间:2024/06/05 08:57
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被占用了



参考链接 
http://lib.csdn.net/article/ios/49652

0 0