使用方法:新建一个catogary,把下面代码分别拷贝到.h和.m文件中,
介绍:foundation框架的参数错误,数组越界等异常捕获,确保app不会崩溃。
方法:运行时技术,在运行时将系统方法替换为我们自己实现的方法
ps:本文只实现了foundation库的部分方法,其实还可以尝试实现UIKit的方法,实现页面数据和用户行为统计等

.h文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#import <Foundation/Foundation.h>

@interface NSArray (swArray)

- (id)sw_objectAtIndex:(NSUInteger)index;

@end

@interface NSMutableArray (swMutableArray)

- (id)sw_objectAtIndex:(NSUInteger)index;
- (void)sw_insertObject:(id)anObject atIndex:(NSUInteger)index;

@end

@interface NSMutableDictionary (swMutableDictionary)

- (void)sw_setObject:(id)anObject forKey:(id<NSCopying>)aKey;

@end

.m文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#import "Swizzl_Foundation.h"
#import <objc/runtime.h>

@implementation NSArray (swArray)
+ (void)load {
[super load];

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{

SEL originalSelector = @selector(objectAtIndex:);
SEL swizzledSelector = @selector(sw_objectAtIndex:);

Method originalMethod = class_getInstanceMethod(objc_getClass("__NSArrayI"), originalSelector);
Method swizzledMethod = class_getInstanceMethod(objc_getClass("__NSArrayI"), swizzledSelector);

method_exchangeImplementations(originalMethod, swizzledMethod);
});
}

-(id)sw_objectAtIndex:(NSUInteger)index {
@try {
return [self sw_objectAtIndex:index];
}
@catch (NSException *exception) {
// 在崩溃后会打印崩溃信息,方便我们调试。
NSLog(@"---------- %s Crash Because Method %s  ----------\n", class_getName(self.class), __func__);
NSLog(@"%@",exception.callStackSymbols);
return nil;
}
@finally {

}
}
@end

@implementation NSMutableArray (swMutableArray)

+ (void)load {
[super load];

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{

{
SEL originalSelector = @selector(objectAtIndex:);
SEL swizzledSelector = @selector(sw_objectAtIndex:);

Method originalMethod = class_getInstanceMethod(objc_getClass("__NSArrayM"), originalSelector);
Method swizzledMethod = class_getInstanceMethod(objc_getClass("__NSArrayM"), swizzledSelector);

method_exchangeImplementations(originalMethod, swizzledMethod);
}
{
SEL originalSelector = @selector(insertObject:atIndex:);
SEL swizzledSelector = @selector(sw_insertObject:atIndex:);

Method originalMethod = class_getInstanceMethod(objc_getClass("__NSArrayM"), originalSelector);
Method swizzledMethod = class_getInstanceMethod(objc_getClass("__NSArrayM"), swizzledSelector);

method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}

-(id)sw_objectAtIndex:(NSUInteger)index {
@try {
return [self sw_objectAtIndex:index];
}
@catch (NSException *exception) {
// 在崩溃后会打印崩溃信息,方便我们调试。
NSLog(@"---------- %s Crash Because Method %s  ----------\n", class_getName(self.class), __func__);
NSLog(@"%@",exception.callStackSymbols);
return nil;
}
@finally {

}
}

- (void)sw_insertObject:(id)anObject atIndex:(NSUInteger)index {
@try {
[self sw_insertObject:anObject atIndex:index];
}
@catch (NSException *exception) {
//如果value和key都非法,系统会先检测到value异常
//value异常:参数为nil
//key异常,数组越界
if ([exception.name isEqualToString:NSInvalidArgumentException]) {
@try {
[self sw_insertObject:[NSNull null] atIndex:index];
}
@catch (NSException *exception) {
// 在崩溃后会打印崩溃信息,方便我们调试。
NSLog(@"---------- %s Crash Because Method %s  ----------\n", class_getName(self.class), __func__);
NSLog(@"%@",exception.callStackSymbols);
if ([exception.name isEqualToString:NSRangeException]) {
// [self sw_insertObject:[NSNull null] atIndex:0];
}
}
@finally {

}
} else {
// [self sw_insertObject:anObject atIndex:0];
}
// 在崩溃后会打印崩溃信息,方便我们调试。
NSLog(@"---------- %s Crash Because Method %s  ----------\n", class_getName(self.class), __func__);
NSLog(@"%@",exception.callStackSymbols);
}
@finally {

}
}

@end

@implementation NSMutableDictionary (swMutableDictionary)

+ (void)load {
[super load];

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{

SEL originalSelector = @selector(setObject:forKey:);
SEL swizzledSelector = @selector(sw_setObject:forKey:);

Method originalMethod = class_getInstanceMethod(objc_getClass("__NSDictionaryM"), originalSelector);
Method swizzledMethod = class_getInstanceMethod(objc_getClass("__NSDictionaryM"), swizzledSelector);

method_exchangeImplementations(originalMethod, swizzledMethod);
});
}

-(void)sw_setObject:(id)anObject forKey:(id<NSCopying>)aKey {
@try {
[self sw_setObject:anObject forKey:aKey];
}
@catch (NSException *exception) {
// 在崩溃后会打印崩溃信息,方便我们调试。
NSLog(@"---------- %s Crash Because Method %s  ----------\n", class_getName(self.class), __func__);
NSLog(@"%@",exception.callStackSymbols);
[self sw_setObject:[NSNull null] forKey:aKey];
}
@finally {

}
}

@end

demo github 地址