首先加入一个小知识:

SEL、Method、IMP的含义及区别

在运行时,类(Class)维护了一个消息分发列表来解决消息的正确发送。每一个消息列表的入口是一个方法(Method),这个方法映射了一对键值对,其中键是这个方法的名字(SEL),值是指向这个方法实现的函数指针 implementation(IMP)。
伪代码表示:

Class {
MethodList (
Method{
SEL:IMP;
}
Method{
SEL:IMP;
}
);
};

Method Swizzling就是改变类的消息分发列表来让消息解析时从一个选择器(SEL)对应到另外一个的实现(IMP),同时将原始的方法实现混淆到一个新的选择器(SEL)。

对Swizzling方法封装

//

//  NSObject+Swizzling.h

//  Swizzling

//

//  Created by peter.zhang on 2016/12/14.

//  Copyright © 2016年 Peter. All rights reserved.

//

#import <Foundation/Foundation.h>

#import <objc/runtime.h>

@interface NSObject (Swizzling)

/**

* Adds a new method to a class with a given name and implementation.

*

* @param originalSelector 原来的方法

* @param swizzledSelector 替换成的方法

*

*/

+ (void)methodSwizzlingWithOriginalSelector:(SEL)originalSelector

bySwizzledSelector:(SEL)swizzledSelector;

@end

//

//  NSObject+Swizzling.m

//  Swizzling

//

//  Created by peter.zhang on 2016/12/14.

//  Copyright © 2016年 Peter. All rights reserved.

//

#import "NSObject+Swizzling.h"

@implementation NSObject (Swizzling)

+ (void)methodSwizzlingWithOriginalSelector:(SEL)originalSelector bySwizzledSelector:(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

-------------------------------以上是对Swizzling方法封装类别--------------------------------

runtime有很多用途:改变ViewController的生命周期、app热更新、改变系统方法调度(解决获取索引、添加、删除元素越界崩溃问题)等。今天主要说数组或者字典的越界crash问题。

啥都不是了,你把Swizzling方法封装类别添加到工程中:

以可变数组为例子:

//

//  NSMutableArray+Security.h

//  Swizzling

//

//  Created by peter.zhang on 2016/12/14.

//  Copyright © 2016年 Peter. All rights reserved.

//

#import <Foundation/Foundation.h>

@interface NSMutableArray (Security)

@end

//

//  NSMutableArray+Security.m

//  Swizzling

//

//  Created by peter.zhang on 2016/12/14.

//  Copyright © 2016年 Peter. All rights reserved.

//

#import "NSMutableArray+Security.h"

#import "NSObject+Swizzling.h"

@implementation NSMutableArray (Security)

+ (void)load {

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

[objc_getClass("__NSArrayM") methodSwizzlingWithOriginalSelector:@selector(removeObject:) bySwizzledSelector:@selector(safeRemoveObject:) ];

[objc_getClass("__NSArrayM") methodSwizzlingWithOriginalSelector:@selector(addObject:) bySwizzledSelector:@selector(safeAddObject:)];

[objc_getClass("__NSArrayM") methodSwizzlingWithOriginalSelector:@selector(removeObjectAtIndex:) bySwizzledSelector:@selector(safeRemoveObjectAtIndex:)];

[objc_getClass("__NSArrayM") methodSwizzlingWithOriginalSelector:@selector(insertObject:atIndex:) bySwizzledSelector:@selector(safeInsertObject:atIndex:)];

[objc_getClass("__NSArrayM") methodSwizzlingWithOriginalSelector:@selector(objectAtIndex:) bySwizzledSelector:@selector(safeObjectAtIndex:)];

});

}

- (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];

}

@end

然后你在工程中用可变数组的增删改查都不会crash了。

Runtime 函数 Swizzling 改变OC方法的调度顺序的更多相关文章

  1. iOS runtime探究(三): 从runtime開始理解OC的属性property

    你要知道的runtime都在这里 转载请注明出处 http://blog.csdn.net/u014205968/article/details/67639303 本文主要解说runtime相关知识, ...

  2. OC方法交换swizzle详细介绍——不再有盲点

    原文链接:https://www.cnblogs.com/mddblog/p/11105450.html 如果对方法交换已经比较熟悉,可以跳过整体介绍,直接看常见问题部分 整体介绍 方法交换是runt ...

  3. ES5——函数,对象,方法,this

    JS由表达式和语句组成 表达式:计算出一个值,但并不进行任何操作,不改变计算机运行状态 语句:包括 声明语句,赋值语句,控制结构 函数,对象,方法,this 数组和对象:是两个非常重要的数据类型 函数 ...

  4. [iOS Hybrid实践:UIWebView中Html中用JS调用OC方法,OC执行JS代码]

    原理: 1.JS调用OC 每次webview执行跳转时都会被iOS给拦截,执行下面函数获得系统允许. 因此可以根据跳转信息转给系统,执行相应功能,比如打开相册等. // 网页中的每一个请求都会被触发 ...

  5. 利用Objective-C运行时hook函数的三种方法

    版权声明:转载请注明出处:http://blog.csdn.net/hursing 方法一,hook已有公开头文件的类: 首先写一个Utility函数: #import <objc/runtim ...

  6. OC方法和文件编译

    OC方法和文件编译 一.OC方法 (一)对象方法 (1)对象方法以-开头如 -(void)xx; (2)对象方法只能又对象来调用 (3)对象方法中可以访问当前对象的成员变量 (4)调用格式   [对象 ...

  7. PHP使用feof()函数读文件的方法

    这篇文章主要介绍了PHP使用feof()函数读文件的方法,以实例形式对比了正确与错误的用法,阐明了feof()函数的使用技巧,需要的朋友可以参考下 本文实例讲述了PHP使用feof()函数读文件的方法 ...

  8. [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法

    js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...

  9. Objective-C Runtime 运行时之三:方法与消息

    基础数据类型 SEL SEL又叫选择器,是表示一个方法的selector的指针,其定义如下: typedef struct objc_selector *SEL; objc_selector结构体的详 ...

随机推荐

  1. android网络优化

    Android---优化下载让网络访问更高效(二) ListView异步加载图片实现思路(优化篇) Android之ListView异步加载网络图片(优化缓存机制) android 网络加载图片,对图 ...

  2. 2D多边形碰撞器优化器

    http://www.unity蛮牛.com/thread-19827-1-1.html http://pan.baidu.com/s/1qW2mWS8 Asset Store Link: http: ...

  3. ZOJ 2110 Tempter of the Bone(DFS)

    点我看题目 题意 : 一个N×M的迷宫,D是门的位置,门会在第T秒开启,而开启时间小于1秒,问能否在T秒的时候到达门的位置,如果能输出YES,否则NO. 思路 :DFS一下就可以,不过要注意下一终止条 ...

  4. POJ 2195 Going Home(最小费用最大流)

    http://poj.org/problem?id=2195 题意 :  N*M的点阵中,有N个人,N个房子.让x个人走到这x个房子中,只能上下左右走,每个人每走一步就花1美元,问当所有的人都归位了之 ...

  5. 归纳决策树ID3(Java实现)

    先上问题吧,我们统计了14天的气象数据(指标包括outlook,temperature,humidity,windy),并已知这些天气是否打球(play).如果给出新一天的气象指标数据:sunny,c ...

  6. 使用Win32/ATL建立窗口的过程

    有时候想写个几十kb的小程序,MFC实在是太大了,Win32有时又太麻烦,怎么办呢?用ATL写会更方便和轻量级一些 ATL和MFC不同的是,ATL并没有强制性封装WinMain函数,仅封装了WndPr ...

  7. 用PowerShell批量部署wsp包

    转:http://www.xuebuyuan.com/168337.html 提供wsp部署的参数: $wsppath:wsp文件所在的路径,如"c:\" $wspnames:路径 ...

  8. import project后,出现Unable to get system library for the project

    import project 后,出现Unable to get system library for the project. 这是因为在import 一个项目的时候,没有指定android sdk ...

  9. 利用Testng注释实现多线程并发测试

    Testng 是一款非常优秀的测试框架,真正从测试角度出发,为测试所想.在测试过程中我们经常会遇到对某一个场景做并发请求,主要想了解该程序在并发时是否会有异常或者没考虑到的其他情况,这时往往不是要做性 ...

  10. Raspberry Pi使用USB摄像头远程监控

    用到了开源项目:MJPG-streamer 开源项目的下载地址: http://sourceforge.net/p/mjpg-streamer/code/HEAD/tree/mjpg-streamer ...