赞
踩
Runtime:
就是在程序运行的过程中,有一套C语言级别的API,它把代码从OC转换成C
OC是基于C,并添加了面向对象的特性,将很多静态语言在编译和链接时做的事放到了runtime运行时来处理
C:函数的调用在编译时就知道会调用哪个函数
OC:在编译的时候并不知道,只在正在运行时才会根据函数名称找到对应的函数
获取属性、方法、成员变量、协议(包括私有的)
给分类动态添加属性、方法
字典转模型
拦截并替换方法
实现NSCoding的归档和反归档
Runtime对注册的类会进行布局,对于weak对象会放入一个hash表中,用weak指向的`对象的内存地址`作为key。当对象的引用计数为0时会调用dealloc方法,此时会在weak表中搜索,将所有weak对象置为nil。
Key:对象内存地址 — value:n个weak对象
以下是使用内容:
- // NSObject+Swizzling.h
- + (void)methodSwizzlingWithOriginalSelector:(SEL)originalSelector bySwizzledSelector:(SEL)swizzledSelector;
-
-
- // NSObject+Swizzling.m
- + (void)methodSwizzlingWithOriginalSelector:(SEL)originalSelector bySwizzledSelector:(SEL)swizzledSelector {
- Class class = [self class];
- // 原有方法
- Method originalMethod = class_getInstanceMethod(class, originalSelector);
- // 新方法
- Method swizzledMetod = class_getInstanceMethod(class, swizzledSelector);
- // 尝试添加`origin`方法
- BOOL didAddMethod = class_addMethod(class,
- originalSelector,
- method_getImplementation(swizzledMetod),
- method_getTypeEncoding(swizzledMetod));
- if (didAddMethod) { // 之前没有实现`origin`方法
- class_replaceMethod(class,
- swizzledSelector,
- method_getImplementation(originalMethod),
- method_getTypeEncoding(originalMethod));
- } else {
- method_exchangeImplementations(originalMethod, swizzledMetod);
- }
- }

- // UIViewController+Swizzling.m
- + (void)load {
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- [self methodSwizzlingWithOriginalSelector:@selector(viewWillDisappear:) bySwizzledSelector:@selector(mo_viewWillDisappear:)];
- });
- }
-
- - (void)mo_viewWillDisappear:(BOOL)animated {
- [self mo_viewWillDisappear:animated];
- // 添加埋点等
- }
类 真身
NSArray __NSArrayI
NSMutableArray __NSArrayM
NSDictionary __NSDictionaryI
NSMutableDictionary __NSDictionaryM
- // NSMutableArray+Swizzling.m
- + (void)load {
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- // objc_getClass("__NSArrayM") 没有用 [self class] 处理,是因为运行时用了`类簇` 运行时正在的类是前者
- [objc_getClass("__NSArrayM") methodSwizzlingWithOriginalSelector:@selector(addObject:) bySwizzledSelector:@selector(safeAddObject:)];
- [objc_getClass("__NSArrayM") methodSwizzlingWithOriginalSelector:@selector(insertObject:atIndex:) bySwizzledSelector:@selector(safeInsertObject:atIndex:)];
- [objc_getClass("__NSArrayM") methodSwizzlingWithOriginalSelector:@selector(objectAtIndex:) bySwizzledSelector:@selector(safeObjectAtIndex:)];
- [objc_getClass("__NSArrayM") methodSwizzlingWithOriginalSelector:@selector(removeObjectAtIndex:) bySwizzledSelector:@selector(safeRemoveObjectAtIndex:)];
- [objc_getClass("__NSArrayM") methodSwizzlingWithOriginalSelector:@selector(removeObject:) bySwizzledSelector:@selector(safeRemoveObject:) ];
- });
- }
- - (void)safeAddObject:(id)obj {
- if (obj == nil) {
- NSLog(@"%s can add nil object into NSMutableArray", __FUNCTION__);
- } else {
- [self safeAddObject:obj];
- }
- }
- - (void)safeRemoveObject:(id)obj {
- if (obj == nil) {
- NSLog(@"%s call -removeObject:, but argument obj is nil", __FUNCTION__);
- return;
- }
- [self safeRemoveObject:obj];
- }
- - (void)safeInsertObject:(id)anObject atIndex:(NSUInteger)index {
- if (anObject == nil) {
- NSLog(@"%s can't insert nil into NSMutableArray", __FUNCTION__);
- } else if (index > self.count) {
- NSLog(@"%s index is invalid", __FUNCTION__);
- } else {
- [self safeInsertObject:anObject atIndex:index];
- }
- }
- - (id)safeObjectAtIndex:(NSUInteger)index {
- if (self.count == 0) {
- NSLog(@"%s can't get any object from an empty array", __FUNCTION__);
- return nil;
- }
- if (index > self.count) {
- NSLog(@"%s index out of bounds in array", __FUNCTION__);
- return nil;
- }
- return [self safeObjectAtIndex:index];
- }
- - (void)safeRemoveObjectAtIndex:(NSUInteger)index {
- if (self.count <= 0) {
- NSLog(@"%s can't get any object from an empty array", __FUNCTION__);
- return;
- }
- if (index >= self.count) {
- NSLog(@"%s index out of bound", __FUNCTION__);
- return;
- }
- [self safeRemoveObjectAtIndex:index];
- }

- // UIButton+Swizzling.m
- + (void)load {
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- [self methodSwizzlingWithOriginalSelector:@selector(sendAction:to:forEvent:) bySwizzledSelector:@selector(mo_sendAction:to:forEvent:)];
- });
- }
-
- // 当按钮点击事件 sendAction 时将会执行 mo_sendAction
- - (void)mo_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
- if (self.isIgnore) { // 不需要被hook
- [self mo_sendAction:action to:target forEvent:event];
- return;
- }
- if ([NSStringFromClass(self.class) isEqualToString:@"UIButton"]) {
- if (self.isIgnoreEvent) {
- return;
- } else {
- self.timeInterval = self.timeInterval == 0 ? defaultInterval : self.timeInterval; // 是否自定义,否则用默认值
- [self performSelector:@selector(resetState) withObject:nil afterDelay:defaultInterval];
- }
- }
- // 此处 methodA 和 methodB方法IMP互换了,实际上执行 sendAction;所以不会死循环
- self.isIgnoreEvent = YES;
- [self mo_sendAction:action to:target forEvent:event]; // 执行系统的原有方法
- }
- // 还有些属性,没添加,详情见Demo

- // UILabel+Swizzling.m
- + (void)load {
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- [self methodSwizzlingWithOriginalSelector:@selector(init) bySwizzledSelector:@selector(mo_Init)];
- [self methodSwizzlingWithOriginalSelector:@selector(initWithFrame:) bySwizzledSelector:@selector(mo_InitWithFrame:)];
- [self methodSwizzlingWithOriginalSelector:@selector(awakeFromNib) bySwizzledSelector:@selector(mo_AwakeFromNib)];
- });
- }
- - (instancetype)mo_Init {
- id __self = [self mo_Init];
- UIFont *font = [UIFont fontWithName:@"Zapfino" size:self.font.pointSize];
- if (font) {
- self.font = font;
- }
- return __self;
- }
- - (instancetype)mo_InitWithFrame:(CGRect)rect {
- id __self = [self mo_InitWithFrame:rect];
- UIFont *font = [UIFont fontWithName:@"Zapfino" size:self.font.pointSize];
- if (font) {
- self.font = font;
- }
- return __self;
- }
- - (void)mo_AwakeFromNib {
- [self mo_AwakeFromNib];
- UIFont *font = [UIFont fontWithName:@"Zapfino" size:self.font.pointSize];
- if (font) {
- self.font = font;
- }
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。