├── .gitignore ├── AvoidCrash.podspec ├── AvoidCrash ├── AvoidCrash.h ├── AvoidCrash.m ├── AvoidCrashProtocol.h ├── AvoidCrashStubProxy.h ├── AvoidCrashStubProxy.m ├── NSArray+AvoidCrash.h ├── NSArray+AvoidCrash.m ├── NSAttributedString+AvoidCrash.h ├── NSAttributedString+AvoidCrash.m ├── NSDictionary+AvoidCrash.h ├── NSDictionary+AvoidCrash.m ├── NSMutableArray+AvoidCrash.h ├── NSMutableArray+AvoidCrash.m ├── NSMutableAttributedString+AvoidCrash.h ├── NSMutableAttributedString+AvoidCrash.m ├── NSMutableDictionary+AvoidCrash.h ├── NSMutableDictionary+AvoidCrash.m ├── NSMutableString+AvoidCrash.h ├── NSMutableString+AvoidCrash.m ├── NSObject+AvoidCrash.h ├── NSObject+AvoidCrash.m ├── NSString+AvoidCrash.h └── NSString+AvoidCrash.m ├── AvoidCrashDemo ├── AvoidCrashDemo.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── AvoidCrashDemo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── AvoidCrashPerson.h │ ├── AvoidCrashPerson.m │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ ├── Person.h │ ├── Person.m │ ├── ViewController.h │ ├── ViewController.m │ └── main.m ├── AvoidCrashDemoTests │ ├── AvoidCrashDemoTests.m │ └── Info.plist ├── AvoidCrashDemoUITests │ ├── AvoidCrashDemoUITests.m │ └── Info.plist └── Screenshot │ ├── Leaks.png │ ├── MIT.svg │ ├── platform.svg │ ├── userInfo信息结构.png │ ├── userInfo详细信息.png │ ├── 崩溃截图.png │ ├── 视频课程 │ ├── MJ_课程2.jpeg │ └── iOS开发高手课.jpeg │ ├── 配置mutableArray.png │ └── 防止崩溃的输出日志.png ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xcuserstate 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | *.ipa 27 | *.dSYM.zip 28 | *.dSYM 29 | 30 | # CocoaPods 31 | # 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 35 | # 36 | # Pods/ 37 | 38 | # Carthage 39 | # 40 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 41 | # Carthage/Checkouts 42 | 43 | Carthage/Build 44 | 45 | # fastlane 46 | # 47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 48 | # screenshots whenever they are needed. 49 | # For more information about the recommended setup visit: 50 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 51 | 52 | fastlane/report.xml 53 | fastlane/screenshots 54 | 55 | #Code Injection 56 | # 57 | # After new code Injection tools there's a generated folder /iOSInjectionProject 58 | # https://github.com/johnno1962/injectionforxcode 59 | 60 | iOSInjectionProject/ 61 | -------------------------------------------------------------------------------- /AvoidCrash.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "AvoidCrash" 3 | s.platform = :ios, "7.0" 4 | s.version = "2.5.2" 5 | s.ios.deployment_target = '7.0' 6 | s.summary = "This framework can avoid Foundation framework potential crash danger" 7 | s.homepage = "https://github.com/chenfanfang/AvoidCrash" 8 | s.license = "MIT" 9 | s.author = { "陈蕃坊" => "493336001@qq.com" } 10 | s.social_media_url = "http://www.jianshu.com/users/80fadb71940d/latest_articles" 11 | s.source = { :git => "https://github.com/chenfanfang/AvoidCrash.git", :tag => s.version } 12 | 13 | s.source_files = 'AvoidCrash/**/*.{h,m}' 14 | s.requires_arc = [ 15 | 'AvoidCrash/AvoidCrash.m', 16 | 'AvoidCrash/AvoidCrashStubProxy.m', 17 | 'AvoidCrash/NSObject+AvoidCrash.m', 18 | 'AvoidCrash/NSArray+AvoidCrash.m', 19 | 'AvoidCrash/NSDictionary+AvoidCrash.m', 20 | 'AvoidCrash/NSMutableDictionary+AvoidCrash.m', 21 | 'AvoidCrash/NSString+AvoidCrash.m', 22 | 'AvoidCrash/NSMutableString+AvoidCrash.m', 23 | 'AvoidCrash/NSAttributedString+AvoidCrash.m', 24 | 'AvoidCrash/NSMutableAttributedString+AvoidCrash.m'] 25 | 26 | 27 | end 28 | 29 | 30 | -------------------------------------------------------------------------------- /AvoidCrash/AvoidCrash.h: -------------------------------------------------------------------------------- 1 | // 2 | // AvoidCrash.h 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/9/21. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | //=================================================== 10 | // 使用方法和注意事项: 11 | // https://www.jianshu.com/p/2b90aa96c0a0 12 | //=================================================== 13 | 14 | #import 15 | #import 16 | 17 | //category 18 | #import "NSObject+AvoidCrash.h" 19 | 20 | #import "NSArray+AvoidCrash.h" 21 | #import "NSMutableArray+AvoidCrash.h" 22 | 23 | #import "NSDictionary+AvoidCrash.h" 24 | #import "NSMutableDictionary+AvoidCrash.h" 25 | 26 | #import "NSString+AvoidCrash.h" 27 | #import "NSMutableString+AvoidCrash.h" 28 | 29 | #import "NSAttributedString+AvoidCrash.h" 30 | #import "NSMutableAttributedString+AvoidCrash.h" 31 | 32 | //define 33 | #import "AvoidCrashStubProxy.h" 34 | 35 | 36 | 37 | 38 | 39 | @interface AvoidCrash : NSObject 40 | 41 | //=================================================== 42 | // 使用方法和注意事项: 43 | // https://www.jianshu.com/p/2b90aa96c0a0 44 | //=================================================== 45 | 46 | 47 | 48 | /** 49 | * 50 | * 开始生效.你可以在AppDelegate的didFinishLaunchingWithOptions方法中调用becomeEffective方法 51 | * 【默认不开启 对”unrecognized selector sent to instance”防止崩溃的处理】 52 | * 53 | * 这是全局生效,若你只需要部分生效,你可以单个进行处理,比如: 54 | * [NSArray avoidCrashExchangeMethod]; 55 | * [NSMutableArray avoidCrashExchangeMethod]; 56 | * ................. 57 | * ................. 58 | * 59 | */ 60 | + (void)becomeEffective; 61 | 62 | 63 | /** 64 | * 相比于becomeEffective,增加 65 | * 对”unrecognized selector sent to instance”防止崩溃的处理 66 | * 67 | * 但是必须配合: 68 | * setupClassStringsArr:和 69 | * setupNoneSelClassStringPrefixsArr 70 | * 这两个方法可以同时使用 71 | */ 72 | + (void)makeAllEffective; 73 | 74 | 75 | 76 | /** 77 | * 初始化一个需要防止”unrecognized selector sent to instance”的崩溃的类名数组 78 | * ⚠️不可将@"NSObject"加入classStrings数组中 79 | * ⚠️不可将UI前缀的字符串加入classStrings数组中 80 | */ 81 | + (void)setupNoneSelClassStringsArr:(NSArray *)classStrings; 82 | 83 | 84 | /** 85 | * 初始化一个需要防止”unrecognized selector sent to instance”的崩溃的类名前缀的数组 86 | * ⚠️不可将UI前缀的字符串(包括@"UI")加入classStringPrefixs数组中 87 | * ⚠️不可将NS前缀的字符串(包括@"NS")加入classStringPrefixs数组中 88 | */ 89 | + (void)setupNoneSelClassStringPrefixsArr:(NSArray *)classStringPrefixs; 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | //您可以忽略以下方法 108 | 109 | + (void)exchangeClassMethod:(Class)anClass method1Sel:(SEL)method1Sel method2Sel:(SEL)method2Sel; 110 | 111 | + (void)exchangeInstanceMethod:(Class)anClass method1Sel:(SEL)method1Sel method2Sel:(SEL)method2Sel; 112 | 113 | + (void)noteErrorWithException:(NSException *)exception defaultToDo:(NSString *)defaultToDo; 114 | 115 | 116 | @end 117 | -------------------------------------------------------------------------------- /AvoidCrash/AvoidCrash.m: -------------------------------------------------------------------------------- 1 | // 2 | // AvoidCrash.m 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/9/21. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import "AvoidCrash.h" 10 | 11 | 12 | 13 | 14 | #define key_errorName @"errorName" 15 | #define key_errorReason @"errorReason" 16 | #define key_errorPlace @"errorPlace" 17 | #define key_defaultToDo @"defaultToDo" 18 | #define key_callStackSymbols @"callStackSymbols" 19 | #define key_exception @"exception" 20 | 21 | 22 | @implementation AvoidCrash 23 | 24 | 25 | + (void)becomeEffective { 26 | [self effectiveIfDealWithNoneSel:NO]; 27 | 28 | } 29 | 30 | + (void)makeAllEffective { 31 | [self effectiveIfDealWithNoneSel:YES]; 32 | } 33 | 34 | + (void)effectiveIfDealWithNoneSel:(BOOL)dealWithNoneSel { 35 | static dispatch_once_t onceToken; 36 | dispatch_once(&onceToken, ^{ 37 | 38 | [NSObject avoidCrashExchangeMethodIfDealWithNoneSel:dealWithNoneSel]; 39 | 40 | [NSArray avoidCrashExchangeMethod]; 41 | [NSMutableArray avoidCrashExchangeMethod]; 42 | 43 | [NSDictionary avoidCrashExchangeMethod]; 44 | [NSMutableDictionary avoidCrashExchangeMethod]; 45 | 46 | [NSString avoidCrashExchangeMethod]; 47 | [NSMutableString avoidCrashExchangeMethod]; 48 | 49 | [NSAttributedString avoidCrashExchangeMethod]; 50 | [NSMutableAttributedString avoidCrashExchangeMethod]; 51 | }); 52 | } 53 | 54 | + (void)setupNoneSelClassStringsArr:(NSArray *)classStrings { 55 | [NSObject setupNoneSelClassStringsArr:classStrings]; 56 | } 57 | 58 | /** 59 | * 初始化一个需要防止”unrecognized selector sent to instance”的崩溃的类名前缀的数组 60 | */ 61 | + (void)setupNoneSelClassStringPrefixsArr:(NSArray *)classStringPrefixs { 62 | [NSObject setupNoneSelClassStringPrefixsArr:classStringPrefixs]; 63 | } 64 | 65 | 66 | /** 67 | * 类方法的交换 68 | * 69 | * @param anClass 哪个类 70 | * @param method1Sel 方法1 71 | * @param method2Sel 方法2 72 | */ 73 | + (void)exchangeClassMethod:(Class)anClass method1Sel:(SEL)method1Sel method2Sel:(SEL)method2Sel { 74 | Method method1 = class_getClassMethod(anClass, method1Sel); 75 | Method method2 = class_getClassMethod(anClass, method2Sel); 76 | method_exchangeImplementations(method1, method2); 77 | } 78 | 79 | 80 | /** 81 | * 对象方法的交换 82 | * 83 | * @param anClass 哪个类 84 | * @param method1Sel 方法1(原本的方法) 85 | * @param method2Sel 方法2(要替换成的方法) 86 | */ 87 | + (void)exchangeInstanceMethod:(Class)anClass method1Sel:(SEL)method1Sel method2Sel:(SEL)method2Sel { 88 | 89 | 90 | Method originalMethod = class_getInstanceMethod(anClass, method1Sel); 91 | Method swizzledMethod = class_getInstanceMethod(anClass, method2Sel); 92 | 93 | BOOL didAddMethod = 94 | class_addMethod(anClass, 95 | method1Sel, 96 | method_getImplementation(swizzledMethod), 97 | method_getTypeEncoding(swizzledMethod)); 98 | 99 | if (didAddMethod) { 100 | class_replaceMethod(anClass, 101 | method2Sel, 102 | method_getImplementation(originalMethod), 103 | method_getTypeEncoding(originalMethod)); 104 | } 105 | 106 | else { 107 | method_exchangeImplementations(originalMethod, swizzledMethod); 108 | } 109 | 110 | } 111 | 112 | 113 | 114 | /** 115 | * 获取堆栈主要崩溃精简化的信息<根据正则表达式匹配出来> 116 | * 117 | * @param callStackSymbols 堆栈主要崩溃信息 118 | * 119 | * @return 堆栈主要崩溃精简化的信息 120 | */ 121 | 122 | + (NSString *)getMainCallStackSymbolMessageWithCallStackSymbols:(NSArray *)callStackSymbols { 123 | 124 | //mainCallStackSymbolMsg的格式为 +[类名 方法名] 或者 -[类名 方法名] 125 | __block NSString *mainCallStackSymbolMsg = nil; 126 | 127 | //匹配出来的格式为 +[类名 方法名] 或者 -[类名 方法名] 128 | NSString *regularExpStr = @"[-\\+]\\[.+\\]"; 129 | 130 | 131 | NSRegularExpression *regularExp = [[NSRegularExpression alloc] initWithPattern:regularExpStr options:NSRegularExpressionCaseInsensitive error:nil]; 132 | 133 | 134 | for (int index = 2; index < callStackSymbols.count; index++) { 135 | NSString *callStackSymbol = callStackSymbols[index]; 136 | 137 | [regularExp enumerateMatchesInString:callStackSymbol options:NSMatchingReportProgress range:NSMakeRange(0, callStackSymbol.length) usingBlock:^(NSTextCheckingResult * _Nullable result, NSMatchingFlags flags, BOOL * _Nonnull stop) { 138 | if (result) { 139 | NSString* tempCallStackSymbolMsg = [callStackSymbol substringWithRange:result.range]; 140 | 141 | //get className 142 | NSString *className = [tempCallStackSymbolMsg componentsSeparatedByString:@" "].firstObject; 143 | className = [className componentsSeparatedByString:@"["].lastObject; 144 | 145 | NSBundle *bundle = [NSBundle bundleForClass:NSClassFromString(className)]; 146 | 147 | //filter category and system class 148 | if (![className hasSuffix:@")"] && bundle == [NSBundle mainBundle]) { 149 | mainCallStackSymbolMsg = tempCallStackSymbolMsg; 150 | 151 | } 152 | *stop = YES; 153 | } 154 | }]; 155 | 156 | if (mainCallStackSymbolMsg.length) { 157 | break; 158 | } 159 | } 160 | 161 | return mainCallStackSymbolMsg; 162 | } 163 | 164 | 165 | /** 166 | * 提示崩溃的信息(控制台输出、通知) 167 | * 168 | * @param exception 捕获到的异常 169 | * @param defaultToDo 这个框架里默认的做法 170 | */ 171 | + (void)noteErrorWithException:(NSException *)exception defaultToDo:(NSString *)defaultToDo { 172 | 173 | //堆栈数据 174 | NSArray *callStackSymbolsArr = [NSThread callStackSymbols]; 175 | 176 | //获取在哪个类的哪个方法中实例化的数组 字符串格式 -[类名 方法名] 或者 +[类名 方法名] 177 | NSString *mainCallStackSymbolMsg = [AvoidCrash getMainCallStackSymbolMessageWithCallStackSymbols:callStackSymbolsArr]; 178 | 179 | if (mainCallStackSymbolMsg == nil) { 180 | 181 | mainCallStackSymbolMsg = @"崩溃方法定位失败,请您查看函数调用栈来排查错误原因"; 182 | 183 | } 184 | 185 | NSString *errorName = exception.name; 186 | NSString *errorReason = exception.reason; 187 | //errorReason 可能为 -[__NSCFConstantString avoidCrashCharacterAtIndex:]: Range or index out of bounds 188 | //将avoidCrash去掉 189 | errorReason = [errorReason stringByReplacingOccurrencesOfString:@"avoidCrash" withString:@""]; 190 | 191 | NSString *errorPlace = [NSString stringWithFormat:@"Error Place:%@",mainCallStackSymbolMsg]; 192 | 193 | NSString *logErrorMessage = [NSString stringWithFormat:@"\n\n%@\n\n%@\n%@\n%@\n%@",AvoidCrashSeparatorWithFlag, errorName, errorReason, errorPlace, defaultToDo]; 194 | 195 | logErrorMessage = [NSString stringWithFormat:@"%@\n\n%@\n\n",logErrorMessage,AvoidCrashSeparator]; 196 | AvoidCrashLog(@"%@",logErrorMessage); 197 | 198 | 199 | //请忽略下面的赋值,目的只是为了能顺利上传到cocoapods 200 | logErrorMessage = logErrorMessage; 201 | 202 | NSDictionary *errorInfoDic = @{ 203 | key_errorName : errorName, 204 | key_errorReason : errorReason, 205 | key_errorPlace : errorPlace, 206 | key_defaultToDo : defaultToDo, 207 | key_exception : exception, 208 | key_callStackSymbols : callStackSymbolsArr 209 | }; 210 | 211 | //将错误信息放在字典里,用通知的形式发送出去 212 | dispatch_async(dispatch_get_main_queue(), ^{ 213 | [[NSNotificationCenter defaultCenter] postNotificationName:AvoidCrashNotification object:nil userInfo:errorInfoDic]; 214 | }); 215 | } 216 | 217 | 218 | 219 | @end 220 | -------------------------------------------------------------------------------- /AvoidCrash/AvoidCrashProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // AvoidCrashProtocol.h 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by chenfanfang on 2017/7/22. 6 | // Copyright © 2017年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @protocol AvoidCrashProtocol 13 | 14 | @required 15 | + (void)avoidCrashExchangeMethod; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /AvoidCrash/AvoidCrashStubProxy.h: -------------------------------------------------------------------------------- 1 | // 2 | // AvoidCrashStubProxy.h 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by chenfanfang on 2017/7/25. 6 | // Copyright © 2017年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | #define AvoidCrashNotification @"AvoidCrashNotification" 13 | #define AvoidCrashIsiOS(version) ([[UIDevice currentDevice].systemVersion floatValue] >= version) 14 | 15 | 16 | //user can ignore below define 17 | #define AvoidCrashDefaultReturnNil @"AvoidCrash default is to return nil to avoid crash." 18 | #define AvoidCrashDefaultIgnore @"AvoidCrash default is to ignore this operation to avoid crash." 19 | 20 | #define AvoidCrashSeparator @"================================================================" 21 | #define AvoidCrashSeparatorWithFlag @"========================AvoidCrash Log==========================" 22 | 23 | 24 | #ifdef DEBUG 25 | 26 | #define AvoidCrashLog(...) NSLog(@"%@",[NSString stringWithFormat:__VA_ARGS__]) 27 | 28 | #else 29 | 30 | #define AvoidCrashLog(...) 31 | #endif 32 | 33 | @interface AvoidCrashStubProxy : NSObject 34 | 35 | - (void)proxyMethod; 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /AvoidCrash/AvoidCrashStubProxy.m: -------------------------------------------------------------------------------- 1 | // 2 | // AvoidCrashStubProxy.m 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by chenfanfang on 2017/7/25. 6 | // Copyright © 2017年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import "AvoidCrashStubProxy.h" 10 | 11 | 12 | @implementation AvoidCrashStubProxy 13 | 14 | - (void)proxyMethod { 15 | 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /AvoidCrash/NSArray+AvoidCrash.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+AvoidCrash.h 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/9/21. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AvoidCrashProtocol.h" 11 | 12 | @interface NSArray (AvoidCrash) 13 | 14 | 15 | @end 16 | 17 | 18 | /** 19 | * Can avoid crash method 20 | * 21 | * 1. NSArray的快速创建方式 NSArray *array = @[@"chenfanfang", @"AvoidCrash"]; //这种创建方式其实调用的是2中的方法 22 | * 2. +(instancetype)arrayWithObjects:(const id _Nonnull __unsafe_unretained *)objects count:(NSUInteger)cnt 23 | * 3. - (id)objectAtIndex:(NSUInteger)index 24 | * 4. - (void)getObjects:(__unsafe_unretained id _Nonnull *)objects range:(NSRange)range 25 | */ 26 | -------------------------------------------------------------------------------- /AvoidCrash/NSArray+AvoidCrash.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+AvoidCrash.m 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/9/21. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import "NSArray+AvoidCrash.h" 10 | 11 | #import "AvoidCrash.h" 12 | 13 | @implementation NSArray (AvoidCrash) 14 | 15 | 16 | + (void)avoidCrashExchangeMethod { 17 | 18 | static dispatch_once_t onceToken; 19 | dispatch_once(&onceToken, ^{ 20 | //================= 21 | // class method 22 | //================= 23 | 24 | //instance array method exchange 25 | [AvoidCrash exchangeClassMethod:[self class] method1Sel:@selector(arrayWithObjects:count:) method2Sel:@selector(AvoidCrashArrayWithObjects:count:)]; 26 | 27 | 28 | 29 | //==================== 30 | // instance method 31 | //==================== 32 | 33 | Class __NSArray = NSClassFromString(@"NSArray"); 34 | Class __NSArrayI = NSClassFromString(@"__NSArrayI"); 35 | Class __NSSingleObjectArrayI = NSClassFromString(@"__NSSingleObjectArrayI"); 36 | Class __NSArray0 = NSClassFromString(@"__NSArray0"); 37 | 38 | 39 | //objectsAtIndexes: 40 | [AvoidCrash exchangeInstanceMethod:__NSArray method1Sel:@selector(objectsAtIndexes:) method2Sel:@selector(avoidCrashObjectsAtIndexes:)]; 41 | 42 | 43 | //objectAtIndex: 44 | 45 | [AvoidCrash exchangeInstanceMethod:__NSArrayI method1Sel:@selector(objectAtIndex:) method2Sel:@selector(__NSArrayIAvoidCrashObjectAtIndex:)]; 46 | 47 | [AvoidCrash exchangeInstanceMethod:__NSSingleObjectArrayI method1Sel:@selector(objectAtIndex:) method2Sel:@selector(__NSSingleObjectArrayIAvoidCrashObjectAtIndex:)]; 48 | 49 | [AvoidCrash exchangeInstanceMethod:__NSArray0 method1Sel:@selector(objectAtIndex:) method2Sel:@selector(__NSArray0AvoidCrashObjectAtIndex:)]; 50 | 51 | //objectAtIndexedSubscript: 52 | if (AvoidCrashIsiOS(11.0)) { 53 | [AvoidCrash exchangeInstanceMethod:__NSArrayI method1Sel:@selector(objectAtIndexedSubscript:) method2Sel:@selector(__NSArrayIAvoidCrashObjectAtIndexedSubscript:)]; 54 | } 55 | 56 | 57 | //getObjects:range: 58 | [AvoidCrash exchangeInstanceMethod:__NSArray method1Sel:@selector(getObjects:range:) method2Sel:@selector(NSArrayAvoidCrashGetObjects:range:)]; 59 | 60 | [AvoidCrash exchangeInstanceMethod:__NSSingleObjectArrayI method1Sel:@selector(getObjects:range:) method2Sel:@selector(__NSSingleObjectArrayIAvoidCrashGetObjects:range:)]; 61 | 62 | [AvoidCrash exchangeInstanceMethod:__NSArrayI method1Sel:@selector(getObjects:range:) method2Sel:@selector(__NSArrayIAvoidCrashGetObjects:range:)]; 63 | }); 64 | 65 | 66 | } 67 | 68 | 69 | //================================================================= 70 | // instance array 71 | //================================================================= 72 | #pragma mark - instance array 73 | 74 | 75 | + (instancetype)AvoidCrashArrayWithObjects:(const id _Nonnull __unsafe_unretained *)objects count:(NSUInteger)cnt { 76 | 77 | id instance = nil; 78 | 79 | @try { 80 | instance = [self AvoidCrashArrayWithObjects:objects count:cnt]; 81 | } 82 | @catch (NSException *exception) { 83 | 84 | NSString *defaultToDo = @"AvoidCrash default is to remove nil object and instance a array."; 85 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 86 | 87 | //以下是对错误数据的处理,把为nil的数据去掉,然后初始化数组 88 | NSInteger newObjsIndex = 0; 89 | id _Nonnull __unsafe_unretained newObjects[cnt]; 90 | 91 | for (int i = 0; i < cnt; i++) { 92 | if (objects[i] != nil) { 93 | newObjects[newObjsIndex] = objects[i]; 94 | newObjsIndex++; 95 | } 96 | } 97 | instance = [self AvoidCrashArrayWithObjects:newObjects count:newObjsIndex]; 98 | } 99 | @finally { 100 | return instance; 101 | } 102 | } 103 | 104 | 105 | 106 | //================================================================= 107 | // objectAtIndexedSubscript: 108 | //================================================================= 109 | #pragma mark - objectAtIndexedSubscript: 110 | - (id)__NSArrayIAvoidCrashObjectAtIndexedSubscript:(NSUInteger)idx { 111 | id object = nil; 112 | 113 | @try { 114 | object = [self __NSArrayIAvoidCrashObjectAtIndexedSubscript:idx]; 115 | } 116 | @catch (NSException *exception) { 117 | NSString *defaultToDo = AvoidCrashDefaultReturnNil; 118 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 119 | } 120 | @finally { 121 | return object; 122 | } 123 | 124 | } 125 | 126 | 127 | //================================================================= 128 | // objectsAtIndexes: 129 | //================================================================= 130 | #pragma mark - objectsAtIndexes: 131 | 132 | - (NSArray *)avoidCrashObjectsAtIndexes:(NSIndexSet *)indexes { 133 | 134 | NSArray *returnArray = nil; 135 | @try { 136 | returnArray = [self avoidCrashObjectsAtIndexes:indexes]; 137 | } @catch (NSException *exception) { 138 | NSString *defaultToDo = AvoidCrashDefaultReturnNil; 139 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 140 | 141 | } @finally { 142 | return returnArray; 143 | } 144 | } 145 | 146 | 147 | //================================================================= 148 | // objectAtIndex: 149 | //================================================================= 150 | #pragma mark - objectAtIndex: 151 | 152 | //__NSArrayI objectAtIndex: 153 | - (id)__NSArrayIAvoidCrashObjectAtIndex:(NSUInteger)index { 154 | id object = nil; 155 | 156 | @try { 157 | object = [self __NSArrayIAvoidCrashObjectAtIndex:index]; 158 | } 159 | @catch (NSException *exception) { 160 | NSString *defaultToDo = AvoidCrashDefaultReturnNil; 161 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 162 | } 163 | @finally { 164 | return object; 165 | } 166 | } 167 | 168 | 169 | 170 | //__NSSingleObjectArrayI objectAtIndex: 171 | - (id)__NSSingleObjectArrayIAvoidCrashObjectAtIndex:(NSUInteger)index { 172 | id object = nil; 173 | 174 | @try { 175 | object = [self __NSSingleObjectArrayIAvoidCrashObjectAtIndex:index]; 176 | } 177 | @catch (NSException *exception) { 178 | NSString *defaultToDo = AvoidCrashDefaultReturnNil; 179 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 180 | } 181 | @finally { 182 | return object; 183 | } 184 | } 185 | 186 | //__NSArray0 objectAtIndex: 187 | - (id)__NSArray0AvoidCrashObjectAtIndex:(NSUInteger)index { 188 | id object = nil; 189 | 190 | @try { 191 | object = [self __NSArray0AvoidCrashObjectAtIndex:index]; 192 | } 193 | @catch (NSException *exception) { 194 | NSString *defaultToDo = AvoidCrashDefaultReturnNil; 195 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 196 | } 197 | @finally { 198 | return object; 199 | } 200 | } 201 | 202 | 203 | //================================================================= 204 | // getObjects:range: 205 | //================================================================= 206 | #pragma mark - getObjects:range: 207 | 208 | //NSArray getObjects:range: 209 | - (void)NSArrayAvoidCrashGetObjects:(__unsafe_unretained id _Nonnull *)objects range:(NSRange)range { 210 | 211 | @try { 212 | [self NSArrayAvoidCrashGetObjects:objects range:range]; 213 | } @catch (NSException *exception) { 214 | 215 | NSString *defaultToDo = AvoidCrashDefaultIgnore; 216 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 217 | 218 | } @finally { 219 | 220 | } 221 | } 222 | 223 | 224 | //__NSSingleObjectArrayI getObjects:range: 225 | - (void)__NSSingleObjectArrayIAvoidCrashGetObjects:(__unsafe_unretained id _Nonnull *)objects range:(NSRange)range { 226 | 227 | @try { 228 | [self __NSSingleObjectArrayIAvoidCrashGetObjects:objects range:range]; 229 | } @catch (NSException *exception) { 230 | 231 | NSString *defaultToDo = AvoidCrashDefaultIgnore; 232 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 233 | 234 | } @finally { 235 | 236 | } 237 | } 238 | 239 | 240 | //__NSArrayI getObjects:range: 241 | - (void)__NSArrayIAvoidCrashGetObjects:(__unsafe_unretained id _Nonnull *)objects range:(NSRange)range { 242 | 243 | @try { 244 | [self __NSArrayIAvoidCrashGetObjects:objects range:range]; 245 | } @catch (NSException *exception) { 246 | 247 | NSString *defaultToDo = AvoidCrashDefaultIgnore; 248 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 249 | 250 | } @finally { 251 | 252 | } 253 | } 254 | 255 | 256 | 257 | 258 | @end 259 | -------------------------------------------------------------------------------- /AvoidCrash/NSAttributedString+AvoidCrash.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSAttributedString+AvoidCrash.h 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/10/15. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AvoidCrashProtocol.h" 11 | 12 | @interface NSAttributedString (AvoidCrash) 13 | 14 | 15 | @end 16 | 17 | /** 18 | * Can avoid crash method 19 | * 20 | * 1.- (instancetype)initWithString:(NSString *)str 21 | * 2.- (instancetype)initWithAttributedString:(NSAttributedString *)attrStr 22 | * 3.- (instancetype)initWithString:(NSString *)str attributes:(NSDictionary *)attrs 23 | * 24 | * 25 | */ 26 | -------------------------------------------------------------------------------- /AvoidCrash/NSAttributedString+AvoidCrash.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSAttributedString+AvoidCrash.m 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/10/15. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import "NSAttributedString+AvoidCrash.h" 10 | 11 | #import "AvoidCrash.h" 12 | 13 | @implementation NSAttributedString (AvoidCrash) 14 | 15 | + (void)avoidCrashExchangeMethod { 16 | 17 | static dispatch_once_t onceToken; 18 | dispatch_once(&onceToken, ^{ 19 | 20 | Class NSConcreteAttributedString = NSClassFromString(@"NSConcreteAttributedString"); 21 | 22 | //initWithString: 23 | [AvoidCrash exchangeInstanceMethod:NSConcreteAttributedString method1Sel:@selector(initWithString:) method2Sel:@selector(avoidCrashInitWithString:)]; 24 | 25 | //initWithAttributedString 26 | [AvoidCrash exchangeInstanceMethod:NSConcreteAttributedString method1Sel:@selector(initWithAttributedString:) method2Sel:@selector(avoidCrashInitWithAttributedString:)]; 27 | 28 | //initWithString:attributes: 29 | [AvoidCrash exchangeInstanceMethod:NSConcreteAttributedString method1Sel:@selector(initWithString:attributes:) method2Sel:@selector(avoidCrashInitWithString:attributes:)]; 30 | }); 31 | 32 | } 33 | 34 | //================================================================= 35 | // initWithString: 36 | //================================================================= 37 | #pragma mark - initWithString: 38 | 39 | - (instancetype)avoidCrashInitWithString:(NSString *)str { 40 | id object = nil; 41 | 42 | @try { 43 | object = [self avoidCrashInitWithString:str]; 44 | } 45 | @catch (NSException *exception) { 46 | NSString *defaultToDo = AvoidCrashDefaultReturnNil; 47 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 48 | } 49 | @finally { 50 | return object; 51 | } 52 | } 53 | 54 | 55 | //================================================================= 56 | // initWithAttributedString 57 | //================================================================= 58 | #pragma mark - initWithAttributedString 59 | 60 | - (instancetype)avoidCrashInitWithAttributedString:(NSAttributedString *)attrStr { 61 | id object = nil; 62 | 63 | @try { 64 | object = [self avoidCrashInitWithAttributedString:attrStr]; 65 | } 66 | @catch (NSException *exception) { 67 | NSString *defaultToDo = AvoidCrashDefaultReturnNil; 68 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 69 | } 70 | @finally { 71 | return object; 72 | } 73 | } 74 | 75 | 76 | //================================================================= 77 | // initWithString:attributes: 78 | //================================================================= 79 | #pragma mark - initWithString:attributes: 80 | 81 | - (instancetype)avoidCrashInitWithString:(NSString *)str attributes:(NSDictionary *)attrs { 82 | id object = nil; 83 | 84 | @try { 85 | object = [self avoidCrashInitWithString:str attributes:attrs]; 86 | } 87 | @catch (NSException *exception) { 88 | NSString *defaultToDo = AvoidCrashDefaultReturnNil; 89 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 90 | } 91 | @finally { 92 | return object; 93 | } 94 | } 95 | 96 | @end 97 | -------------------------------------------------------------------------------- /AvoidCrash/NSDictionary+AvoidCrash.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSDictionary+AvoidCrash.h 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/9/21. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AvoidCrashProtocol.h" 11 | 12 | @interface NSDictionary (AvoidCrash) 13 | 14 | 15 | @end 16 | 17 | 18 | /** 19 | * Can avoid crash method 20 | * 21 | * 1. NSDictionary的快速创建方式 NSDictionary *dict = @{@"frameWork" : @"AvoidCrash"}; //这种创建方式其实调用的是2中的方法 22 | * 2. +(instancetype)dictionaryWithObjects:(const id _Nonnull __unsafe_unretained *)objects forKeys:(const id _Nonnull __unsafe_unretained *)keys count:(NSUInteger)cnt 23 | * 24 | */ 25 | -------------------------------------------------------------------------------- /AvoidCrash/NSDictionary+AvoidCrash.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSDictionary+AvoidCrash.m 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/9/21. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import "NSDictionary+AvoidCrash.h" 10 | 11 | #import "AvoidCrash.h" 12 | 13 | @implementation NSDictionary (AvoidCrash) 14 | 15 | + (void)avoidCrashExchangeMethod { 16 | 17 | static dispatch_once_t onceToken; 18 | dispatch_once(&onceToken, ^{ 19 | 20 | [AvoidCrash exchangeClassMethod:self method1Sel:@selector(dictionaryWithObjects:forKeys:count:) method2Sel:@selector(avoidCrashDictionaryWithObjects:forKeys:count:)]; 21 | }); 22 | } 23 | 24 | 25 | + (instancetype)avoidCrashDictionaryWithObjects:(const id _Nonnull __unsafe_unretained *)objects forKeys:(const id _Nonnull __unsafe_unretained *)keys count:(NSUInteger)cnt { 26 | 27 | id instance = nil; 28 | 29 | @try { 30 | instance = [self avoidCrashDictionaryWithObjects:objects forKeys:keys count:cnt]; 31 | } 32 | @catch (NSException *exception) { 33 | 34 | NSString *defaultToDo = @"AvoidCrash default is to remove nil key-values and instance a dictionary."; 35 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 36 | 37 | //处理错误的数据,然后重新初始化一个字典 38 | NSUInteger index = 0; 39 | id _Nonnull __unsafe_unretained newObjects[cnt]; 40 | id _Nonnull __unsafe_unretained newkeys[cnt]; 41 | 42 | for (int i = 0; i < cnt; i++) { 43 | if (objects[i] && keys[i]) { 44 | newObjects[index] = objects[i]; 45 | newkeys[index] = keys[i]; 46 | index++; 47 | } 48 | } 49 | instance = [self avoidCrashDictionaryWithObjects:newObjects forKeys:newkeys count:index]; 50 | } 51 | @finally { 52 | return instance; 53 | } 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /AvoidCrash/NSMutableArray+AvoidCrash.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableArray+AvoidCrash.h 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/9/21. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AvoidCrashProtocol.h" 11 | 12 | @interface NSMutableArray (AvoidCrash) 13 | 14 | 15 | @end 16 | 17 | 18 | /** 19 | * Can avoid crash method 20 | * 21 | * 1. - (id)objectAtIndex:(NSUInteger)index 22 | * 2. - (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx 23 | * 3. - (void)removeObjectAtIndex:(NSUInteger)index 24 | * 4. - (void)insertObject:(id)anObject atIndex:(NSUInteger)index 25 | * 5. - (void)getObjects:(__unsafe_unretained id _Nonnull *)objects range:(NSRange)range 26 | */ 27 | -------------------------------------------------------------------------------- /AvoidCrash/NSMutableArray+AvoidCrash.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableArray+AvoidCrash.m 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/9/21. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import "NSMutableArray+AvoidCrash.h" 10 | 11 | #import "AvoidCrash.h" 12 | 13 | @implementation NSMutableArray (AvoidCrash) 14 | 15 | + (void)avoidCrashExchangeMethod { 16 | 17 | static dispatch_once_t onceToken; 18 | dispatch_once(&onceToken, ^{ 19 | 20 | Class arrayMClass = NSClassFromString(@"__NSArrayM"); 21 | 22 | 23 | //objectAtIndex: 24 | [AvoidCrash exchangeInstanceMethod:arrayMClass method1Sel:@selector(objectAtIndex:) method2Sel:@selector(avoidCrashObjectAtIndex:)]; 25 | 26 | //objectAtIndexedSubscript 27 | if (AvoidCrashIsiOS(11.0)) { 28 | [AvoidCrash exchangeInstanceMethod:arrayMClass method1Sel:@selector(objectAtIndexedSubscript:) method2Sel:@selector(avoidCrashObjectAtIndexedSubscript:)]; 29 | } 30 | 31 | 32 | //setObject:atIndexedSubscript: 33 | [AvoidCrash exchangeInstanceMethod:arrayMClass method1Sel:@selector(setObject:atIndexedSubscript:) method2Sel:@selector(avoidCrashSetObject:atIndexedSubscript:)]; 34 | 35 | 36 | //removeObjectAtIndex: 37 | [AvoidCrash exchangeInstanceMethod:arrayMClass method1Sel:@selector(removeObjectAtIndex:) method2Sel:@selector(avoidCrashRemoveObjectAtIndex:)]; 38 | 39 | //insertObject:atIndex: 40 | [AvoidCrash exchangeInstanceMethod:arrayMClass method1Sel:@selector(insertObject:atIndex:) method2Sel:@selector(avoidCrashInsertObject:atIndex:)]; 41 | 42 | //getObjects:range: 43 | [AvoidCrash exchangeInstanceMethod:arrayMClass method1Sel:@selector(getObjects:range:) method2Sel:@selector(avoidCrashGetObjects:range:)]; 44 | }); 45 | 46 | 47 | 48 | } 49 | 50 | 51 | //================================================================= 52 | // array set object at index 53 | //================================================================= 54 | #pragma mark - get object from array 55 | 56 | 57 | - (void)avoidCrashSetObject:(id)obj atIndexedSubscript:(NSUInteger)idx { 58 | 59 | @try { 60 | [self avoidCrashSetObject:obj atIndexedSubscript:idx]; 61 | } 62 | @catch (NSException *exception) { 63 | [AvoidCrash noteErrorWithException:exception defaultToDo:AvoidCrashDefaultIgnore]; 64 | } 65 | @finally { 66 | 67 | } 68 | } 69 | 70 | 71 | //================================================================= 72 | // removeObjectAtIndex: 73 | //================================================================= 74 | #pragma mark - removeObjectAtIndex: 75 | 76 | - (void)avoidCrashRemoveObjectAtIndex:(NSUInteger)index { 77 | @try { 78 | [self avoidCrashRemoveObjectAtIndex:index]; 79 | } 80 | @catch (NSException *exception) { 81 | [AvoidCrash noteErrorWithException:exception defaultToDo:AvoidCrashDefaultIgnore]; 82 | } 83 | @finally { 84 | 85 | } 86 | } 87 | 88 | 89 | //================================================================= 90 | // insertObject:atIndex: 91 | //================================================================= 92 | #pragma mark - set方法 93 | - (void)avoidCrashInsertObject:(id)anObject atIndex:(NSUInteger)index { 94 | @try { 95 | [self avoidCrashInsertObject:anObject atIndex:index]; 96 | } 97 | @catch (NSException *exception) { 98 | [AvoidCrash noteErrorWithException:exception defaultToDo:AvoidCrashDefaultIgnore]; 99 | } 100 | @finally { 101 | 102 | } 103 | } 104 | 105 | 106 | //================================================================= 107 | // objectAtIndex: 108 | //================================================================= 109 | #pragma mark - objectAtIndex: 110 | 111 | - (id)avoidCrashObjectAtIndex:(NSUInteger)index { 112 | id object = nil; 113 | 114 | @try { 115 | object = [self avoidCrashObjectAtIndex:index]; 116 | } 117 | @catch (NSException *exception) { 118 | NSString *defaultToDo = AvoidCrashDefaultReturnNil; 119 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 120 | } 121 | @finally { 122 | return object; 123 | } 124 | } 125 | 126 | //================================================================= 127 | // objectAtIndexedSubscript: 128 | //================================================================= 129 | #pragma mark - objectAtIndexedSubscript: 130 | - (id)avoidCrashObjectAtIndexedSubscript:(NSUInteger)idx { 131 | id object = nil; 132 | 133 | @try { 134 | object = [self avoidCrashObjectAtIndexedSubscript:idx]; 135 | } 136 | @catch (NSException *exception) { 137 | NSString *defaultToDo = AvoidCrashDefaultReturnNil; 138 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 139 | } 140 | @finally { 141 | return object; 142 | } 143 | 144 | } 145 | 146 | 147 | //================================================================= 148 | // getObjects:range: 149 | //================================================================= 150 | #pragma mark - getObjects:range: 151 | 152 | - (void)avoidCrashGetObjects:(__unsafe_unretained id _Nonnull *)objects range:(NSRange)range { 153 | 154 | @try { 155 | [self avoidCrashGetObjects:objects range:range]; 156 | } @catch (NSException *exception) { 157 | 158 | NSString *defaultToDo = AvoidCrashDefaultIgnore; 159 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 160 | 161 | } @finally { 162 | 163 | } 164 | } 165 | 166 | 167 | 168 | 169 | @end 170 | -------------------------------------------------------------------------------- /AvoidCrash/NSMutableAttributedString+AvoidCrash.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableAttributedString+AvoidCrash.h 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/10/15. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AvoidCrashProtocol.h" 11 | 12 | @interface NSMutableAttributedString (AvoidCrash) 13 | 14 | 15 | @end 16 | 17 | 18 | /** 19 | * Can avoid crash method 20 | * 21 | * 1.- (instancetype)initWithString:(NSString *)str 22 | * 2.- (instancetype)initWithString:(NSString *)str attributes:(NSDictionary *)attrs 23 | */ 24 | -------------------------------------------------------------------------------- /AvoidCrash/NSMutableAttributedString+AvoidCrash.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableAttributedString+AvoidCrash.m 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/10/15. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import "NSMutableAttributedString+AvoidCrash.h" 10 | 11 | #import "AvoidCrash.h" 12 | 13 | @implementation NSMutableAttributedString (AvoidCrash) 14 | 15 | + (void)avoidCrashExchangeMethod { 16 | 17 | static dispatch_once_t onceToken; 18 | dispatch_once(&onceToken, ^{ 19 | 20 | Class NSConcreteMutableAttributedString = NSClassFromString(@"NSConcreteMutableAttributedString"); 21 | 22 | //initWithString: 23 | [AvoidCrash exchangeInstanceMethod:NSConcreteMutableAttributedString method1Sel:@selector(initWithString:) method2Sel:@selector(avoidCrashInitWithString:)]; 24 | 25 | //initWithString:attributes: 26 | [AvoidCrash exchangeInstanceMethod:NSConcreteMutableAttributedString method1Sel:@selector(initWithString:attributes:) method2Sel:@selector(avoidCrashInitWithString:attributes:)]; 27 | }); 28 | } 29 | 30 | //================================================================= 31 | // initWithString: 32 | //================================================================= 33 | #pragma mark - initWithString: 34 | 35 | 36 | - (instancetype)avoidCrashInitWithString:(NSString *)str { 37 | id object = nil; 38 | 39 | @try { 40 | object = [self avoidCrashInitWithString:str]; 41 | } 42 | @catch (NSException *exception) { 43 | NSString *defaultToDo = AvoidCrashDefaultReturnNil; 44 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 45 | } 46 | @finally { 47 | return object; 48 | } 49 | } 50 | 51 | 52 | //================================================================= 53 | // initWithString:attributes: 54 | //================================================================= 55 | #pragma mark - initWithString:attributes: 56 | 57 | 58 | - (instancetype)avoidCrashInitWithString:(NSString *)str attributes:(NSDictionary *)attrs { 59 | id object = nil; 60 | 61 | @try { 62 | object = [self avoidCrashInitWithString:str attributes:attrs]; 63 | } 64 | @catch (NSException *exception) { 65 | NSString *defaultToDo = AvoidCrashDefaultReturnNil; 66 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 67 | } 68 | @finally { 69 | return object; 70 | } 71 | } 72 | 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /AvoidCrash/NSMutableDictionary+AvoidCrash.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableDictionary+AvoidCrash.h 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/9/22. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AvoidCrashProtocol.h" 11 | 12 | @interface NSMutableDictionary (AvoidCrash) 13 | 14 | 15 | @end 16 | 17 | 18 | /** 19 | * Can avoid crash method 20 | * 21 | * 1. - (void)setObject:(id)anObject forKey:(id)aKey 22 | * 2. - (void)removeObjectForKey:(id)aKey 23 | * 24 | */ 25 | -------------------------------------------------------------------------------- /AvoidCrash/NSMutableDictionary+AvoidCrash.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableDictionary+AvoidCrash.m 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/9/22. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import "NSMutableDictionary+AvoidCrash.h" 10 | 11 | #import "AvoidCrash.h" 12 | 13 | @implementation NSMutableDictionary (AvoidCrash) 14 | 15 | + (void)avoidCrashExchangeMethod { 16 | 17 | static dispatch_once_t onceToken; 18 | dispatch_once(&onceToken, ^{ 19 | Class dictionaryM = NSClassFromString(@"__NSDictionaryM"); 20 | 21 | //setObject:forKey: 22 | [AvoidCrash exchangeInstanceMethod:dictionaryM method1Sel:@selector(setObject:forKey:) method2Sel:@selector(avoidCrashSetObject:forKey:)]; 23 | 24 | //setObject:forKeyedSubscript: 25 | if (AvoidCrashIsiOS(11.0)) { 26 | [AvoidCrash exchangeInstanceMethod:dictionaryM method1Sel:@selector(setObject:forKeyedSubscript:) method2Sel:@selector(avoidCrashSetObject:forKeyedSubscript:)]; 27 | } 28 | 29 | 30 | 31 | //removeObjectForKey: 32 | Method removeObjectForKey = class_getInstanceMethod(dictionaryM, @selector(removeObjectForKey:)); 33 | Method avoidCrashRemoveObjectForKey = class_getInstanceMethod(dictionaryM, @selector(avoidCrashRemoveObjectForKey:)); 34 | method_exchangeImplementations(removeObjectForKey, avoidCrashRemoveObjectForKey); 35 | }); 36 | } 37 | 38 | 39 | //================================================================= 40 | // setObject:forKey: 41 | //================================================================= 42 | #pragma mark - setObject:forKey: 43 | 44 | - (void)avoidCrashSetObject:(id)anObject forKey:(id)aKey { 45 | 46 | @try { 47 | [self avoidCrashSetObject:anObject forKey:aKey]; 48 | } 49 | @catch (NSException *exception) { 50 | [AvoidCrash noteErrorWithException:exception defaultToDo:AvoidCrashDefaultIgnore]; 51 | } 52 | @finally { 53 | 54 | } 55 | } 56 | 57 | //================================================================= 58 | // setObject:forKeyedSubscript: 59 | //================================================================= 60 | #pragma mark - setObject:forKeyedSubscript: 61 | - (void)avoidCrashSetObject:(id)obj forKeyedSubscript:(id)key { 62 | @try { 63 | [self avoidCrashSetObject:obj forKeyedSubscript:key]; 64 | } 65 | @catch (NSException *exception) { 66 | [AvoidCrash noteErrorWithException:exception defaultToDo:AvoidCrashDefaultIgnore]; 67 | } 68 | @finally { 69 | 70 | } 71 | } 72 | 73 | 74 | //================================================================= 75 | // removeObjectForKey: 76 | //================================================================= 77 | #pragma mark - removeObjectForKey: 78 | 79 | - (void)avoidCrashRemoveObjectForKey:(id)aKey { 80 | 81 | @try { 82 | [self avoidCrashRemoveObjectForKey:aKey]; 83 | } 84 | @catch (NSException *exception) { 85 | [AvoidCrash noteErrorWithException:exception defaultToDo:AvoidCrashDefaultIgnore]; 86 | } 87 | @finally { 88 | 89 | } 90 | } 91 | 92 | 93 | 94 | 95 | @end 96 | -------------------------------------------------------------------------------- /AvoidCrash/NSMutableString+AvoidCrash.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableString+AvoidCrash.h 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/10/6. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AvoidCrashProtocol.h" 11 | 12 | @interface NSMutableString (AvoidCrash) 13 | 14 | 15 | @end 16 | 17 | 18 | /** 19 | * Can avoid crash method 20 | * 21 | * 1. 由于NSMutableString是继承于NSString,所以这里和NSString有些同样的方法就不重复写了 22 | * 2. - (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)aString 23 | * 3. - (void)insertString:(NSString *)aString atIndex:(NSUInteger)loc 24 | * 4. - (void)deleteCharactersInRange:(NSRange)range 25 | * 26 | */ 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /AvoidCrash/NSMutableString+AvoidCrash.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableString+AvoidCrash.m 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/10/6. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import "NSMutableString+AvoidCrash.h" 10 | 11 | #import "AvoidCrash.h" 12 | 13 | @implementation NSMutableString (AvoidCrash) 14 | 15 | + (void)avoidCrashExchangeMethod { 16 | 17 | static dispatch_once_t onceToken; 18 | dispatch_once(&onceToken, ^{ 19 | 20 | Class stringClass = NSClassFromString(@"__NSCFString"); 21 | 22 | //replaceCharactersInRange 23 | [AvoidCrash exchangeInstanceMethod:stringClass method1Sel:@selector(replaceCharactersInRange:withString:) method2Sel:@selector(avoidCrashReplaceCharactersInRange:withString:)]; 24 | 25 | //insertString:atIndex: 26 | [AvoidCrash exchangeInstanceMethod:stringClass method1Sel:@selector(insertString:atIndex:) method2Sel:@selector(avoidCrashInsertString:atIndex:)]; 27 | 28 | //deleteCharactersInRange 29 | [AvoidCrash exchangeInstanceMethod:stringClass method1Sel:@selector(deleteCharactersInRange:) method2Sel:@selector(avoidCrashDeleteCharactersInRange:)]; 30 | }); 31 | } 32 | 33 | //================================================================= 34 | // replaceCharactersInRange 35 | //================================================================= 36 | #pragma mark - replaceCharactersInRange 37 | 38 | - (void)avoidCrashReplaceCharactersInRange:(NSRange)range withString:(NSString *)aString { 39 | 40 | @try { 41 | [self avoidCrashReplaceCharactersInRange:range withString:aString]; 42 | } 43 | @catch (NSException *exception) { 44 | NSString *defaultToDo = AvoidCrashDefaultIgnore; 45 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 46 | } 47 | @finally { 48 | 49 | } 50 | } 51 | 52 | //================================================================= 53 | // insertString:atIndex: 54 | //================================================================= 55 | #pragma mark - insertString:atIndex: 56 | 57 | - (void)avoidCrashInsertString:(NSString *)aString atIndex:(NSUInteger)loc { 58 | 59 | @try { 60 | [self avoidCrashInsertString:aString atIndex:loc]; 61 | } 62 | @catch (NSException *exception) { 63 | NSString *defaultToDo = AvoidCrashDefaultIgnore; 64 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 65 | } 66 | @finally { 67 | 68 | } 69 | } 70 | 71 | //================================================================= 72 | // deleteCharactersInRange 73 | //================================================================= 74 | #pragma mark - deleteCharactersInRange 75 | 76 | - (void)avoidCrashDeleteCharactersInRange:(NSRange)range { 77 | 78 | @try { 79 | [self avoidCrashDeleteCharactersInRange:range]; 80 | } 81 | @catch (NSException *exception) { 82 | NSString *defaultToDo = AvoidCrashDefaultIgnore; 83 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 84 | } 85 | @finally { 86 | 87 | } 88 | } 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | @end 98 | -------------------------------------------------------------------------------- /AvoidCrash/NSObject+AvoidCrash.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+AvoidCrash.h 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/10/11. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface NSObject (AvoidCrash) 13 | 14 | /** 15 | * ifDealWithNoneSel : 是否开启"unrecognized selector sent to instance"异常的捕获 16 | */ 17 | + (void)avoidCrashExchangeMethodIfDealWithNoneSel:(BOOL)ifDealWithNoneSel; 18 | 19 | 20 | + (void)setupNoneSelClassStringsArr:(NSArray *)classStrings; 21 | 22 | + (void)setupNoneSelClassStringPrefixsArr:(NSArray *)classStringPrefixs; 23 | 24 | @end 25 | 26 | /** 27 | * Can avoid crash method 28 | * 29 | * 1.- (void)setValue:(id)value forKey:(NSString *)key 30 | * 2.- (void)setValue:(id)value forKeyPath:(NSString *)keyPath 31 | * 3.- (void)setValue:(id)value forUndefinedKey:(NSString *)key //这个方法一般用来重写,不会主动调用 32 | * 4.- (void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues 33 | * 5. unrecognized selector sent to instance 34 | */ 35 | -------------------------------------------------------------------------------- /AvoidCrash/NSObject+AvoidCrash.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+AvoidCrash.m 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/10/11. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import "NSObject+AvoidCrash.h" 10 | #import "AvoidCrash.h" 11 | #import "AvoidCrashStubProxy.h" 12 | 13 | @implementation NSObject (AvoidCrash) 14 | 15 | 16 | + (void)avoidCrashExchangeMethodIfDealWithNoneSel:(BOOL)ifDealWithNoneSel { 17 | 18 | static dispatch_once_t onceToken; 19 | dispatch_once(&onceToken, ^{ 20 | //setValue:forKey: 21 | [AvoidCrash exchangeInstanceMethod:[self class] method1Sel:@selector(setValue:forKey:) method2Sel:@selector(avoidCrashSetValue:forKey:)]; 22 | 23 | //setValue:forKeyPath: 24 | [AvoidCrash exchangeInstanceMethod:[self class] method1Sel:@selector(setValue:forKeyPath:) method2Sel:@selector(avoidCrashSetValue:forKeyPath:)]; 25 | 26 | //setValue:forUndefinedKey: 27 | [AvoidCrash exchangeInstanceMethod:[self class] method1Sel:@selector(setValue:forUndefinedKey:) method2Sel:@selector(avoidCrashSetValue:forUndefinedKey:)]; 28 | 29 | //setValuesForKeysWithDictionary: 30 | [AvoidCrash exchangeInstanceMethod:[self class] method1Sel:@selector(setValuesForKeysWithDictionary:) method2Sel:@selector(avoidCrashSetValuesForKeysWithDictionary:)]; 31 | 32 | 33 | //unrecognized selector sent to instance 34 | if (ifDealWithNoneSel) { 35 | [AvoidCrash exchangeInstanceMethod:[self class] method1Sel:@selector(methodSignatureForSelector:) method2Sel:@selector(avoidCrashMethodSignatureForSelector:)]; 36 | [AvoidCrash exchangeInstanceMethod:[self class] method1Sel:@selector(forwardInvocation:) method2Sel:@selector(avoidCrashForwardInvocation:)]; 37 | } 38 | }); 39 | } 40 | 41 | 42 | //================================================================= 43 | // unrecognized selector sent to instance 44 | //================================================================= 45 | #pragma mark - unrecognized selector sent to instance 46 | 47 | 48 | static NSMutableArray *noneSelClassStrings; 49 | static NSMutableArray *noneSelClassStringPrefixs; 50 | 51 | + (void)setupNoneSelClassStringsArr:(NSArray *)classStrings { 52 | 53 | if (noneSelClassStrings) { 54 | 55 | NSString *warningMsg = [NSString stringWithFormat:@"\n\n%@\n\n[AvoidCrash setupNoneSelClassStringsArr:];\n调用一此即可,多次调用会自动忽略后面的调用\n\n%@\n\n",AvoidCrashSeparatorWithFlag,AvoidCrashSeparator]; 56 | AvoidCrashLog(@"%@",warningMsg); 57 | } 58 | 59 | static dispatch_once_t onceToken; 60 | dispatch_once(&onceToken, ^{ 61 | noneSelClassStrings = [NSMutableArray array]; 62 | for (NSString *className in classStrings) { 63 | if ([className hasPrefix:@"UI"] == NO && 64 | [className isEqualToString:NSStringFromClass([NSObject class])] == NO) { 65 | [noneSelClassStrings addObject:className]; 66 | 67 | } else { 68 | NSString *warningMsg = [NSString stringWithFormat:@"\n\n%@\n\n[AvoidCrash setupNoneSelClassStringsArr:];\n会忽略UI开头的类和NSObject类(请使用NSObject的子类)\n\n%@\n\n",AvoidCrashSeparatorWithFlag,AvoidCrashSeparator]; 69 | AvoidCrashLog(@"%@",warningMsg); 70 | } 71 | } 72 | }); 73 | } 74 | 75 | /** 76 | * 初始化一个需要防止”unrecognized selector sent to instance”的崩溃的类名前缀的数组 77 | */ 78 | + (void)setupNoneSelClassStringPrefixsArr:(NSArray *)classStringPrefixs { 79 | if (noneSelClassStringPrefixs) { 80 | 81 | NSString *warningMsg = [NSString stringWithFormat:@"\n\n%@\n\n[AvoidCrash setupNoneSelClassStringPrefixsArr:];\n调用一此即可,多次调用会自动忽略后面的调用\n\n%@\n\n",AvoidCrashSeparatorWithFlag,AvoidCrashSeparator]; 82 | AvoidCrashLog(@"%@",warningMsg); 83 | } 84 | 85 | static dispatch_once_t onceToken; 86 | dispatch_once(&onceToken, ^{ 87 | 88 | noneSelClassStringPrefixs = [NSMutableArray array]; 89 | for (NSString *classNamePrefix in classStringPrefixs) { 90 | if ([classNamePrefix hasPrefix:@"UI"] == NO && 91 | [classNamePrefix hasPrefix:@"NS"] == NO) { 92 | [noneSelClassStringPrefixs addObject:classNamePrefix]; 93 | 94 | } else { 95 | NSString *warningMsg = [NSString stringWithFormat:@"\n\n%@\n\n[AvoidCrash setupNoneSelClassStringsArr:];\n会忽略UI开头的类和NS开头的类\n若需要对NS开头的类防止”unrecognized selector sent to instance”(比如NSArray),请使用setupNoneSelClassStringsArr:\n\n%@\n\n",AvoidCrashSeparatorWithFlag,AvoidCrashSeparator]; 96 | AvoidCrashLog(@"%@",warningMsg); 97 | } 98 | } 99 | }); 100 | } 101 | 102 | - (NSMethodSignature *)avoidCrashMethodSignatureForSelector:(SEL)aSelector { 103 | 104 | NSMethodSignature *ms = [self avoidCrashMethodSignatureForSelector:aSelector]; 105 | 106 | BOOL flag = NO; 107 | if (ms == nil) { 108 | for (NSString *classStr in noneSelClassStrings) { 109 | if ([self isKindOfClass:NSClassFromString(classStr)]) { 110 | ms = [AvoidCrashStubProxy instanceMethodSignatureForSelector:@selector(proxyMethod)]; 111 | flag = YES; 112 | break; 113 | } 114 | } 115 | } 116 | if (flag == NO) { 117 | NSString *selfClass = NSStringFromClass([self class]); 118 | for (NSString *classStrPrefix in noneSelClassStringPrefixs) { 119 | if ([selfClass hasPrefix:classStrPrefix]) { 120 | ms = [AvoidCrashStubProxy instanceMethodSignatureForSelector:@selector(proxyMethod)]; 121 | } 122 | } 123 | } 124 | return ms; 125 | } 126 | 127 | - (void)avoidCrashForwardInvocation:(NSInvocation *)anInvocation { 128 | 129 | @try { 130 | [self avoidCrashForwardInvocation:anInvocation]; 131 | 132 | } @catch (NSException *exception) { 133 | NSString *defaultToDo = AvoidCrashDefaultIgnore; 134 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 135 | 136 | } @finally { 137 | 138 | } 139 | 140 | } 141 | 142 | 143 | //================================================================= 144 | // setValue:forKey: 145 | //================================================================= 146 | #pragma mark - setValue:forKey: 147 | 148 | - (void)avoidCrashSetValue:(id)value forKey:(NSString *)key { 149 | @try { 150 | [self avoidCrashSetValue:value forKey:key]; 151 | } 152 | @catch (NSException *exception) { 153 | NSString *defaultToDo = AvoidCrashDefaultIgnore; 154 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 155 | } 156 | @finally { 157 | 158 | } 159 | } 160 | 161 | 162 | //================================================================= 163 | // setValue:forKeyPath: 164 | //================================================================= 165 | #pragma mark - setValue:forKeyPath: 166 | 167 | - (void)avoidCrashSetValue:(id)value forKeyPath:(NSString *)keyPath { 168 | @try { 169 | [self avoidCrashSetValue:value forKeyPath:keyPath]; 170 | } 171 | @catch (NSException *exception) { 172 | NSString *defaultToDo = AvoidCrashDefaultIgnore; 173 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 174 | } 175 | @finally { 176 | 177 | } 178 | } 179 | 180 | 181 | 182 | //================================================================= 183 | // setValue:forUndefinedKey: 184 | //================================================================= 185 | #pragma mark - setValue:forUndefinedKey: 186 | 187 | - (void)avoidCrashSetValue:(id)value forUndefinedKey:(NSString *)key { 188 | @try { 189 | [self avoidCrashSetValue:value forUndefinedKey:key]; 190 | } 191 | @catch (NSException *exception) { 192 | NSString *defaultToDo = AvoidCrashDefaultIgnore; 193 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 194 | } 195 | @finally { 196 | 197 | } 198 | } 199 | 200 | 201 | //================================================================= 202 | // setValuesForKeysWithDictionary: 203 | //================================================================= 204 | #pragma mark - setValuesForKeysWithDictionary: 205 | 206 | - (void)avoidCrashSetValuesForKeysWithDictionary:(NSDictionary *)keyedValues { 207 | @try { 208 | [self avoidCrashSetValuesForKeysWithDictionary:keyedValues]; 209 | } 210 | @catch (NSException *exception) { 211 | NSString *defaultToDo = AvoidCrashDefaultIgnore; 212 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 213 | } 214 | @finally { 215 | 216 | } 217 | } 218 | 219 | 220 | 221 | @end 222 | -------------------------------------------------------------------------------- /AvoidCrash/NSString+AvoidCrash.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+AvoidCrash.h 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/10/5. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AvoidCrashProtocol.h" 11 | 12 | @interface NSString (AvoidCrash) 13 | 14 | 15 | @end 16 | 17 | 18 | /** 19 | * Can avoid crash method 20 | * 21 | * 1. - (unichar)characterAtIndex:(NSUInteger)index 22 | * 2. - (NSString *)substringFromIndex:(NSUInteger)from 23 | * 3. - (NSString *)substringToIndex:(NSUInteger)to { 24 | * 4. - (NSString *)substringWithRange:(NSRange)range { 25 | * 5. - (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement 26 | * 6. - (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement options:(NSStringCompareOptions)options range:(NSRange)searchRange 27 | * 7. - (NSString *)stringByReplacingCharactersInRange:(NSRange)range withString:(NSString *)replacement 28 | * 29 | */ 30 | -------------------------------------------------------------------------------- /AvoidCrash/NSString+AvoidCrash.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+AvoidCrash.m 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/10/5. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import "NSString+AvoidCrash.h" 10 | 11 | #import "AvoidCrash.h" 12 | 13 | @implementation NSString (AvoidCrash) 14 | 15 | + (void)avoidCrashExchangeMethod { 16 | 17 | static dispatch_once_t onceToken; 18 | dispatch_once(&onceToken, ^{ 19 | Class stringClass = NSClassFromString(@"__NSCFConstantString"); 20 | 21 | //characterAtIndex 22 | [AvoidCrash exchangeInstanceMethod:stringClass method1Sel:@selector(characterAtIndex:) method2Sel:@selector(avoidCrashCharacterAtIndex:)]; 23 | 24 | //substringFromIndex 25 | [AvoidCrash exchangeInstanceMethod:stringClass method1Sel:@selector(substringFromIndex:) method2Sel:@selector(avoidCrashSubstringFromIndex:)]; 26 | 27 | //substringToIndex 28 | [AvoidCrash exchangeInstanceMethod:stringClass method1Sel:@selector(substringToIndex:) method2Sel:@selector(avoidCrashSubstringToIndex:)]; 29 | 30 | //substringWithRange: 31 | [AvoidCrash exchangeInstanceMethod:stringClass method1Sel:@selector(substringWithRange:) method2Sel:@selector(avoidCrashSubstringWithRange:)]; 32 | 33 | //stringByReplacingOccurrencesOfString: 34 | [AvoidCrash exchangeInstanceMethod:stringClass method1Sel:@selector(stringByReplacingOccurrencesOfString:withString:) method2Sel:@selector(avoidCrashStringByReplacingOccurrencesOfString:withString:)]; 35 | 36 | //stringByReplacingOccurrencesOfString:withString:options:range: 37 | [AvoidCrash exchangeInstanceMethod:stringClass method1Sel:@selector(stringByReplacingOccurrencesOfString:withString:options:range:) method2Sel:@selector(avoidCrashStringByReplacingOccurrencesOfString:withString:options:range:)]; 38 | 39 | //stringByReplacingCharactersInRange:withString: 40 | [AvoidCrash exchangeInstanceMethod:stringClass method1Sel:@selector(stringByReplacingCharactersInRange:withString:) method2Sel:@selector(avoidCrashStringByReplacingCharactersInRange:withString:)]; 41 | }); 42 | 43 | } 44 | 45 | 46 | //================================================================= 47 | // characterAtIndex: 48 | //================================================================= 49 | #pragma mark - characterAtIndex: 50 | 51 | - (unichar)avoidCrashCharacterAtIndex:(NSUInteger)index { 52 | 53 | unichar characteristic; 54 | @try { 55 | characteristic = [self avoidCrashCharacterAtIndex:index]; 56 | } 57 | @catch (NSException *exception) { 58 | 59 | NSString *defaultToDo = @"AvoidCrash default is to return a without assign unichar."; 60 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 61 | } 62 | @finally { 63 | return characteristic; 64 | } 65 | } 66 | 67 | //================================================================= 68 | // substringFromIndex: 69 | //================================================================= 70 | #pragma mark - substringFromIndex: 71 | 72 | - (NSString *)avoidCrashSubstringFromIndex:(NSUInteger)from { 73 | 74 | NSString *subString = nil; 75 | 76 | @try { 77 | subString = [self avoidCrashSubstringFromIndex:from]; 78 | } 79 | @catch (NSException *exception) { 80 | 81 | NSString *defaultToDo = AvoidCrashDefaultReturnNil; 82 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 83 | subString = nil; 84 | } 85 | @finally { 86 | return subString; 87 | } 88 | } 89 | 90 | //================================================================= 91 | // substringToIndex 92 | //================================================================= 93 | #pragma mark - substringToIndex 94 | 95 | - (NSString *)avoidCrashSubstringToIndex:(NSUInteger)to { 96 | 97 | NSString *subString = nil; 98 | 99 | @try { 100 | subString = [self avoidCrashSubstringToIndex:to]; 101 | } 102 | @catch (NSException *exception) { 103 | NSString *defaultToDo = AvoidCrashDefaultReturnNil; 104 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 105 | subString = nil; 106 | } 107 | @finally { 108 | return subString; 109 | } 110 | } 111 | 112 | 113 | //================================================================= 114 | // substringWithRange: 115 | //================================================================= 116 | #pragma mark - substringWithRange: 117 | 118 | - (NSString *)avoidCrashSubstringWithRange:(NSRange)range { 119 | 120 | NSString *subString = nil; 121 | 122 | @try { 123 | subString = [self avoidCrashSubstringWithRange:range]; 124 | } 125 | @catch (NSException *exception) { 126 | NSString *defaultToDo = AvoidCrashDefaultReturnNil; 127 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 128 | subString = nil; 129 | } 130 | @finally { 131 | return subString; 132 | } 133 | } 134 | 135 | //================================================================= 136 | // stringByReplacingOccurrencesOfString: 137 | //================================================================= 138 | #pragma mark - stringByReplacingOccurrencesOfString: 139 | 140 | - (NSString *)avoidCrashStringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement { 141 | 142 | NSString *newStr = nil; 143 | 144 | @try { 145 | newStr = [self avoidCrashStringByReplacingOccurrencesOfString:target withString:replacement]; 146 | } 147 | @catch (NSException *exception) { 148 | NSString *defaultToDo = AvoidCrashDefaultReturnNil; 149 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 150 | newStr = nil; 151 | } 152 | @finally { 153 | return newStr; 154 | } 155 | } 156 | 157 | //================================================================= 158 | // stringByReplacingOccurrencesOfString:withString:options:range: 159 | //================================================================= 160 | #pragma mark - stringByReplacingOccurrencesOfString:withString:options:range: 161 | 162 | - (NSString *)avoidCrashStringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement options:(NSStringCompareOptions)options range:(NSRange)searchRange { 163 | 164 | NSString *newStr = nil; 165 | 166 | @try { 167 | newStr = [self avoidCrashStringByReplacingOccurrencesOfString:target withString:replacement options:options range:searchRange]; 168 | } 169 | @catch (NSException *exception) { 170 | NSString *defaultToDo = AvoidCrashDefaultReturnNil; 171 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 172 | newStr = nil; 173 | } 174 | @finally { 175 | return newStr; 176 | } 177 | } 178 | 179 | 180 | //================================================================= 181 | // stringByReplacingCharactersInRange:withString: 182 | //================================================================= 183 | #pragma mark - stringByReplacingCharactersInRange:withString: 184 | 185 | - (NSString *)avoidCrashStringByReplacingCharactersInRange:(NSRange)range withString:(NSString *)replacement { 186 | 187 | 188 | NSString *newStr = nil; 189 | 190 | @try { 191 | newStr = [self avoidCrashStringByReplacingCharactersInRange:range withString:replacement]; 192 | } 193 | @catch (NSException *exception) { 194 | NSString *defaultToDo = AvoidCrashDefaultReturnNil; 195 | [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo]; 196 | newStr = nil; 197 | } 198 | @finally { 199 | return newStr; 200 | } 201 | } 202 | 203 | 204 | @end 205 | -------------------------------------------------------------------------------- /AvoidCrashDemo/AvoidCrashDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 040330221DACD96E00AE5A41 /* NSObject+AvoidCrash.m in Sources */ = {isa = PBXBuildFile; fileRef = 040330211DACD96E00AE5A41 /* NSObject+AvoidCrash.m */; }; 11 | 043C63E41D938EE100A0B0E9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 043C63E31D938EE100A0B0E9 /* main.m */; }; 12 | 043C63E71D938EE100A0B0E9 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 043C63E61D938EE100A0B0E9 /* AppDelegate.m */; }; 13 | 043C63EA1D938EE100A0B0E9 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 043C63E91D938EE100A0B0E9 /* ViewController.m */; }; 14 | 043C63ED1D938EE100A0B0E9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 043C63EB1D938EE100A0B0E9 /* Main.storyboard */; }; 15 | 043C63EF1D938EE100A0B0E9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 043C63EE1D938EE100A0B0E9 /* Assets.xcassets */; }; 16 | 043C63F21D938EE100A0B0E9 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 043C63F01D938EE100A0B0E9 /* LaunchScreen.storyboard */; }; 17 | 043C63FD1D938EE100A0B0E9 /* AvoidCrashDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 043C63FC1D938EE100A0B0E9 /* AvoidCrashDemoTests.m */; }; 18 | 043C64081D938EE100A0B0E9 /* AvoidCrashDemoUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 043C64071D938EE100A0B0E9 /* AvoidCrashDemoUITests.m */; }; 19 | 043C64201D93A60C00A0B0E9 /* AvoidCrash.m in Sources */ = {isa = PBXBuildFile; fileRef = 043C64171D93A60C00A0B0E9 /* AvoidCrash.m */; }; 20 | 043C64211D93A60C00A0B0E9 /* NSArray+AvoidCrash.m in Sources */ = {isa = PBXBuildFile; fileRef = 043C64191D93A60C00A0B0E9 /* NSArray+AvoidCrash.m */; }; 21 | 043C64221D93A60C00A0B0E9 /* NSDictionary+AvoidCrash.m in Sources */ = {isa = PBXBuildFile; fileRef = 043C641B1D93A60C00A0B0E9 /* NSDictionary+AvoidCrash.m */; }; 22 | 043C64231D93A60C00A0B0E9 /* NSMutableArray+AvoidCrash.m in Sources */ = {isa = PBXBuildFile; fileRef = 043C641D1D93A60C00A0B0E9 /* NSMutableArray+AvoidCrash.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 23 | 043C64241D93A60C00A0B0E9 /* NSMutableDictionary+AvoidCrash.m in Sources */ = {isa = PBXBuildFile; fileRef = 043C641F1D93A60C00A0B0E9 /* NSMutableDictionary+AvoidCrash.m */; }; 24 | 04C3DFD31DA4EED200E18858 /* NSString+AvoidCrash.m in Sources */ = {isa = PBXBuildFile; fileRef = 04C3DFD21DA4EED200E18858 /* NSString+AvoidCrash.m */; }; 25 | 04FB61D91DB2361400C079F2 /* NSAttributedString+AvoidCrash.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FB61D81DB2361400C079F2 /* NSAttributedString+AvoidCrash.m */; }; 26 | 04FB61DC1DB25FE500C079F2 /* NSMutableAttributedString+AvoidCrash.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FB61DB1DB25FE500C079F2 /* NSMutableAttributedString+AvoidCrash.m */; }; 27 | 04FEB8FF1DA55E6B00B5647E /* NSMutableString+AvoidCrash.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FEB8FE1DA55E6B00B5647E /* NSMutableString+AvoidCrash.m */; }; 28 | F61CF29C1FF2206D006093D9 /* AvoidCrashPerson.m in Sources */ = {isa = PBXBuildFile; fileRef = F61CF29B1FF2206D006093D9 /* AvoidCrashPerson.m */; }; 29 | F63018CE1F22EFA000F176DF /* Person.m in Sources */ = {isa = PBXBuildFile; fileRef = F63018CD1F22EFA000F176DF /* Person.m */; }; 30 | F6EBB7B51F271CCB00ED3B15 /* AvoidCrashStubProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = F6EBB7B41F271CCB00ED3B15 /* AvoidCrashStubProxy.m */; }; 31 | /* End PBXBuildFile section */ 32 | 33 | /* Begin PBXContainerItemProxy section */ 34 | 043C63F91D938EE100A0B0E9 /* PBXContainerItemProxy */ = { 35 | isa = PBXContainerItemProxy; 36 | containerPortal = 043C63D71D938EE100A0B0E9 /* Project object */; 37 | proxyType = 1; 38 | remoteGlobalIDString = 043C63DE1D938EE100A0B0E9; 39 | remoteInfo = AvoidCrashDemo; 40 | }; 41 | 043C64041D938EE100A0B0E9 /* PBXContainerItemProxy */ = { 42 | isa = PBXContainerItemProxy; 43 | containerPortal = 043C63D71D938EE100A0B0E9 /* Project object */; 44 | proxyType = 1; 45 | remoteGlobalIDString = 043C63DE1D938EE100A0B0E9; 46 | remoteInfo = AvoidCrashDemo; 47 | }; 48 | /* End PBXContainerItemProxy section */ 49 | 50 | /* Begin PBXFileReference section */ 51 | 040330201DACD96E00AE5A41 /* NSObject+AvoidCrash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+AvoidCrash.h"; sourceTree = ""; }; 52 | 040330211DACD96E00AE5A41 /* NSObject+AvoidCrash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+AvoidCrash.m"; sourceTree = ""; }; 53 | 043C63DF1D938EE100A0B0E9 /* AvoidCrashDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AvoidCrashDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 54 | 043C63E31D938EE100A0B0E9 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 55 | 043C63E51D938EE100A0B0E9 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 56 | 043C63E61D938EE100A0B0E9 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 57 | 043C63E81D938EE100A0B0E9 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 58 | 043C63E91D938EE100A0B0E9 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 59 | 043C63EC1D938EE100A0B0E9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 60 | 043C63EE1D938EE100A0B0E9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 61 | 043C63F11D938EE100A0B0E9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 62 | 043C63F31D938EE100A0B0E9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 63 | 043C63F81D938EE100A0B0E9 /* AvoidCrashDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AvoidCrashDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 64 | 043C63FC1D938EE100A0B0E9 /* AvoidCrashDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AvoidCrashDemoTests.m; sourceTree = ""; }; 65 | 043C63FE1D938EE100A0B0E9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 66 | 043C64031D938EE100A0B0E9 /* AvoidCrashDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AvoidCrashDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 67 | 043C64071D938EE100A0B0E9 /* AvoidCrashDemoUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AvoidCrashDemoUITests.m; sourceTree = ""; }; 68 | 043C64091D938EE100A0B0E9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 69 | 043C64161D93A60C00A0B0E9 /* AvoidCrash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AvoidCrash.h; sourceTree = ""; }; 70 | 043C64171D93A60C00A0B0E9 /* AvoidCrash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AvoidCrash.m; sourceTree = ""; }; 71 | 043C64181D93A60C00A0B0E9 /* NSArray+AvoidCrash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+AvoidCrash.h"; sourceTree = ""; }; 72 | 043C64191D93A60C00A0B0E9 /* NSArray+AvoidCrash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+AvoidCrash.m"; sourceTree = ""; }; 73 | 043C641A1D93A60C00A0B0E9 /* NSDictionary+AvoidCrash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+AvoidCrash.h"; sourceTree = ""; }; 74 | 043C641B1D93A60C00A0B0E9 /* NSDictionary+AvoidCrash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+AvoidCrash.m"; sourceTree = ""; }; 75 | 043C641C1D93A60C00A0B0E9 /* NSMutableArray+AvoidCrash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableArray+AvoidCrash.h"; sourceTree = ""; }; 76 | 043C641D1D93A60C00A0B0E9 /* NSMutableArray+AvoidCrash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableArray+AvoidCrash.m"; sourceTree = ""; }; 77 | 043C641E1D93A60C00A0B0E9 /* NSMutableDictionary+AvoidCrash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableDictionary+AvoidCrash.h"; sourceTree = ""; }; 78 | 043C641F1D93A60C00A0B0E9 /* NSMutableDictionary+AvoidCrash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableDictionary+AvoidCrash.m"; sourceTree = ""; }; 79 | 04C3DFD11DA4EED200E18858 /* NSString+AvoidCrash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+AvoidCrash.h"; sourceTree = ""; }; 80 | 04C3DFD21DA4EED200E18858 /* NSString+AvoidCrash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+AvoidCrash.m"; sourceTree = ""; }; 81 | 04FB61D71DB2361400C079F2 /* NSAttributedString+AvoidCrash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSAttributedString+AvoidCrash.h"; sourceTree = ""; }; 82 | 04FB61D81DB2361400C079F2 /* NSAttributedString+AvoidCrash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSAttributedString+AvoidCrash.m"; sourceTree = ""; }; 83 | 04FB61DA1DB25FE500C079F2 /* NSMutableAttributedString+AvoidCrash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableAttributedString+AvoidCrash.h"; sourceTree = ""; }; 84 | 04FB61DB1DB25FE500C079F2 /* NSMutableAttributedString+AvoidCrash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableAttributedString+AvoidCrash.m"; sourceTree = ""; }; 85 | 04FEB8FD1DA55E6B00B5647E /* NSMutableString+AvoidCrash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableString+AvoidCrash.h"; sourceTree = ""; }; 86 | 04FEB8FE1DA55E6B00B5647E /* NSMutableString+AvoidCrash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableString+AvoidCrash.m"; sourceTree = ""; }; 87 | F61CF29A1FF2206D006093D9 /* AvoidCrashPerson.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AvoidCrashPerson.h; sourceTree = ""; }; 88 | F61CF29B1FF2206D006093D9 /* AvoidCrashPerson.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AvoidCrashPerson.m; sourceTree = ""; }; 89 | F63018CC1F22EFA000F176DF /* Person.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Person.h; sourceTree = ""; }; 90 | F63018CD1F22EFA000F176DF /* Person.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Person.m; sourceTree = ""; }; 91 | F63018D21F23153A00F176DF /* AvoidCrashProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AvoidCrashProtocol.h; sourceTree = ""; }; 92 | F6EBB7B31F271CCB00ED3B15 /* AvoidCrashStubProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AvoidCrashStubProxy.h; sourceTree = ""; }; 93 | F6EBB7B41F271CCB00ED3B15 /* AvoidCrashStubProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AvoidCrashStubProxy.m; sourceTree = ""; }; 94 | /* End PBXFileReference section */ 95 | 96 | /* Begin PBXFrameworksBuildPhase section */ 97 | 043C63DC1D938EE100A0B0E9 /* Frameworks */ = { 98 | isa = PBXFrameworksBuildPhase; 99 | buildActionMask = 2147483647; 100 | files = ( 101 | ); 102 | runOnlyForDeploymentPostprocessing = 0; 103 | }; 104 | 043C63F51D938EE100A0B0E9 /* Frameworks */ = { 105 | isa = PBXFrameworksBuildPhase; 106 | buildActionMask = 2147483647; 107 | files = ( 108 | ); 109 | runOnlyForDeploymentPostprocessing = 0; 110 | }; 111 | 043C64001D938EE100A0B0E9 /* Frameworks */ = { 112 | isa = PBXFrameworksBuildPhase; 113 | buildActionMask = 2147483647; 114 | files = ( 115 | ); 116 | runOnlyForDeploymentPostprocessing = 0; 117 | }; 118 | /* End PBXFrameworksBuildPhase section */ 119 | 120 | /* Begin PBXGroup section */ 121 | 043C63D61D938EE100A0B0E9 = { 122 | isa = PBXGroup; 123 | children = ( 124 | 043C63E11D938EE100A0B0E9 /* AvoidCrashDemo */, 125 | 043C63FB1D938EE100A0B0E9 /* AvoidCrashDemoTests */, 126 | 043C64061D938EE100A0B0E9 /* AvoidCrashDemoUITests */, 127 | 043C63E01D938EE100A0B0E9 /* Products */, 128 | ); 129 | sourceTree = ""; 130 | }; 131 | 043C63E01D938EE100A0B0E9 /* Products */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 043C63DF1D938EE100A0B0E9 /* AvoidCrashDemo.app */, 135 | 043C63F81D938EE100A0B0E9 /* AvoidCrashDemoTests.xctest */, 136 | 043C64031D938EE100A0B0E9 /* AvoidCrashDemoUITests.xctest */, 137 | ); 138 | name = Products; 139 | sourceTree = ""; 140 | }; 141 | 043C63E11D938EE100A0B0E9 /* AvoidCrashDemo */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 043C64151D93A60C00A0B0E9 /* AvoidCrash */, 145 | 043C63E51D938EE100A0B0E9 /* AppDelegate.h */, 146 | 043C63E61D938EE100A0B0E9 /* AppDelegate.m */, 147 | 043C63E81D938EE100A0B0E9 /* ViewController.h */, 148 | 043C63E91D938EE100A0B0E9 /* ViewController.m */, 149 | F63018CC1F22EFA000F176DF /* Person.h */, 150 | F63018CD1F22EFA000F176DF /* Person.m */, 151 | F61CF29A1FF2206D006093D9 /* AvoidCrashPerson.h */, 152 | F61CF29B1FF2206D006093D9 /* AvoidCrashPerson.m */, 153 | 043C63EB1D938EE100A0B0E9 /* Main.storyboard */, 154 | 043C63EE1D938EE100A0B0E9 /* Assets.xcassets */, 155 | 043C63F01D938EE100A0B0E9 /* LaunchScreen.storyboard */, 156 | 043C63F31D938EE100A0B0E9 /* Info.plist */, 157 | 043C63E21D938EE100A0B0E9 /* Supporting Files */, 158 | ); 159 | path = AvoidCrashDemo; 160 | sourceTree = ""; 161 | }; 162 | 043C63E21D938EE100A0B0E9 /* Supporting Files */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | 043C63E31D938EE100A0B0E9 /* main.m */, 166 | ); 167 | name = "Supporting Files"; 168 | sourceTree = ""; 169 | }; 170 | 043C63FB1D938EE100A0B0E9 /* AvoidCrashDemoTests */ = { 171 | isa = PBXGroup; 172 | children = ( 173 | 043C63FC1D938EE100A0B0E9 /* AvoidCrashDemoTests.m */, 174 | 043C63FE1D938EE100A0B0E9 /* Info.plist */, 175 | ); 176 | path = AvoidCrashDemoTests; 177 | sourceTree = ""; 178 | }; 179 | 043C64061D938EE100A0B0E9 /* AvoidCrashDemoUITests */ = { 180 | isa = PBXGroup; 181 | children = ( 182 | 043C64071D938EE100A0B0E9 /* AvoidCrashDemoUITests.m */, 183 | 043C64091D938EE100A0B0E9 /* Info.plist */, 184 | ); 185 | path = AvoidCrashDemoUITests; 186 | sourceTree = ""; 187 | }; 188 | 043C64151D93A60C00A0B0E9 /* AvoidCrash */ = { 189 | isa = PBXGroup; 190 | children = ( 191 | 043C64161D93A60C00A0B0E9 /* AvoidCrash.h */, 192 | 043C64171D93A60C00A0B0E9 /* AvoidCrash.m */, 193 | F6EBB7B31F271CCB00ED3B15 /* AvoidCrashStubProxy.h */, 194 | F6EBB7B41F271CCB00ED3B15 /* AvoidCrashStubProxy.m */, 195 | F63018D21F23153A00F176DF /* AvoidCrashProtocol.h */, 196 | 040330201DACD96E00AE5A41 /* NSObject+AvoidCrash.h */, 197 | 040330211DACD96E00AE5A41 /* NSObject+AvoidCrash.m */, 198 | 043C64181D93A60C00A0B0E9 /* NSArray+AvoidCrash.h */, 199 | 043C64191D93A60C00A0B0E9 /* NSArray+AvoidCrash.m */, 200 | 043C641C1D93A60C00A0B0E9 /* NSMutableArray+AvoidCrash.h */, 201 | 043C641D1D93A60C00A0B0E9 /* NSMutableArray+AvoidCrash.m */, 202 | 043C641A1D93A60C00A0B0E9 /* NSDictionary+AvoidCrash.h */, 203 | 043C641B1D93A60C00A0B0E9 /* NSDictionary+AvoidCrash.m */, 204 | 043C641E1D93A60C00A0B0E9 /* NSMutableDictionary+AvoidCrash.h */, 205 | 043C641F1D93A60C00A0B0E9 /* NSMutableDictionary+AvoidCrash.m */, 206 | 04C3DFD11DA4EED200E18858 /* NSString+AvoidCrash.h */, 207 | 04C3DFD21DA4EED200E18858 /* NSString+AvoidCrash.m */, 208 | 04FEB8FD1DA55E6B00B5647E /* NSMutableString+AvoidCrash.h */, 209 | 04FEB8FE1DA55E6B00B5647E /* NSMutableString+AvoidCrash.m */, 210 | 04FB61D71DB2361400C079F2 /* NSAttributedString+AvoidCrash.h */, 211 | 04FB61D81DB2361400C079F2 /* NSAttributedString+AvoidCrash.m */, 212 | 04FB61DA1DB25FE500C079F2 /* NSMutableAttributedString+AvoidCrash.h */, 213 | 04FB61DB1DB25FE500C079F2 /* NSMutableAttributedString+AvoidCrash.m */, 214 | ); 215 | name = AvoidCrash; 216 | path = ../../AvoidCrash; 217 | sourceTree = ""; 218 | }; 219 | /* End PBXGroup section */ 220 | 221 | /* Begin PBXNativeTarget section */ 222 | 043C63DE1D938EE100A0B0E9 /* AvoidCrashDemo */ = { 223 | isa = PBXNativeTarget; 224 | buildConfigurationList = 043C640C1D938EE100A0B0E9 /* Build configuration list for PBXNativeTarget "AvoidCrashDemo" */; 225 | buildPhases = ( 226 | 043C63DB1D938EE100A0B0E9 /* Sources */, 227 | 043C63DC1D938EE100A0B0E9 /* Frameworks */, 228 | 043C63DD1D938EE100A0B0E9 /* Resources */, 229 | ); 230 | buildRules = ( 231 | ); 232 | dependencies = ( 233 | ); 234 | name = AvoidCrashDemo; 235 | productName = AvoidCrashDemo; 236 | productReference = 043C63DF1D938EE100A0B0E9 /* AvoidCrashDemo.app */; 237 | productType = "com.apple.product-type.application"; 238 | }; 239 | 043C63F71D938EE100A0B0E9 /* AvoidCrashDemoTests */ = { 240 | isa = PBXNativeTarget; 241 | buildConfigurationList = 043C640F1D938EE100A0B0E9 /* Build configuration list for PBXNativeTarget "AvoidCrashDemoTests" */; 242 | buildPhases = ( 243 | 043C63F41D938EE100A0B0E9 /* Sources */, 244 | 043C63F51D938EE100A0B0E9 /* Frameworks */, 245 | 043C63F61D938EE100A0B0E9 /* Resources */, 246 | ); 247 | buildRules = ( 248 | ); 249 | dependencies = ( 250 | 043C63FA1D938EE100A0B0E9 /* PBXTargetDependency */, 251 | ); 252 | name = AvoidCrashDemoTests; 253 | productName = AvoidCrashDemoTests; 254 | productReference = 043C63F81D938EE100A0B0E9 /* AvoidCrashDemoTests.xctest */; 255 | productType = "com.apple.product-type.bundle.unit-test"; 256 | }; 257 | 043C64021D938EE100A0B0E9 /* AvoidCrashDemoUITests */ = { 258 | isa = PBXNativeTarget; 259 | buildConfigurationList = 043C64121D938EE100A0B0E9 /* Build configuration list for PBXNativeTarget "AvoidCrashDemoUITests" */; 260 | buildPhases = ( 261 | 043C63FF1D938EE100A0B0E9 /* Sources */, 262 | 043C64001D938EE100A0B0E9 /* Frameworks */, 263 | 043C64011D938EE100A0B0E9 /* Resources */, 264 | ); 265 | buildRules = ( 266 | ); 267 | dependencies = ( 268 | 043C64051D938EE100A0B0E9 /* PBXTargetDependency */, 269 | ); 270 | name = AvoidCrashDemoUITests; 271 | productName = AvoidCrashDemoUITests; 272 | productReference = 043C64031D938EE100A0B0E9 /* AvoidCrashDemoUITests.xctest */; 273 | productType = "com.apple.product-type.bundle.ui-testing"; 274 | }; 275 | /* End PBXNativeTarget section */ 276 | 277 | /* Begin PBXProject section */ 278 | 043C63D71D938EE100A0B0E9 /* Project object */ = { 279 | isa = PBXProject; 280 | attributes = { 281 | LastUpgradeCheck = 0720; 282 | ORGANIZATIONNAME = chenfanfang; 283 | TargetAttributes = { 284 | 043C63DE1D938EE100A0B0E9 = { 285 | CreatedOnToolsVersion = 7.2.1; 286 | DevelopmentTeam = H659824MAF; 287 | ProvisioningStyle = Manual; 288 | }; 289 | 043C63F71D938EE100A0B0E9 = { 290 | CreatedOnToolsVersion = 7.2.1; 291 | TestTargetID = 043C63DE1D938EE100A0B0E9; 292 | }; 293 | 043C64021D938EE100A0B0E9 = { 294 | CreatedOnToolsVersion = 7.2.1; 295 | TestTargetID = 043C63DE1D938EE100A0B0E9; 296 | }; 297 | }; 298 | }; 299 | buildConfigurationList = 043C63DA1D938EE100A0B0E9 /* Build configuration list for PBXProject "AvoidCrashDemo" */; 300 | compatibilityVersion = "Xcode 3.2"; 301 | developmentRegion = English; 302 | hasScannedForEncodings = 0; 303 | knownRegions = ( 304 | en, 305 | Base, 306 | ); 307 | mainGroup = 043C63D61D938EE100A0B0E9; 308 | productRefGroup = 043C63E01D938EE100A0B0E9 /* Products */; 309 | projectDirPath = ""; 310 | projectRoot = ""; 311 | targets = ( 312 | 043C63DE1D938EE100A0B0E9 /* AvoidCrashDemo */, 313 | 043C63F71D938EE100A0B0E9 /* AvoidCrashDemoTests */, 314 | 043C64021D938EE100A0B0E9 /* AvoidCrashDemoUITests */, 315 | ); 316 | }; 317 | /* End PBXProject section */ 318 | 319 | /* Begin PBXResourcesBuildPhase section */ 320 | 043C63DD1D938EE100A0B0E9 /* Resources */ = { 321 | isa = PBXResourcesBuildPhase; 322 | buildActionMask = 2147483647; 323 | files = ( 324 | 043C63F21D938EE100A0B0E9 /* LaunchScreen.storyboard in Resources */, 325 | 043C63EF1D938EE100A0B0E9 /* Assets.xcassets in Resources */, 326 | 043C63ED1D938EE100A0B0E9 /* Main.storyboard in Resources */, 327 | ); 328 | runOnlyForDeploymentPostprocessing = 0; 329 | }; 330 | 043C63F61D938EE100A0B0E9 /* Resources */ = { 331 | isa = PBXResourcesBuildPhase; 332 | buildActionMask = 2147483647; 333 | files = ( 334 | ); 335 | runOnlyForDeploymentPostprocessing = 0; 336 | }; 337 | 043C64011D938EE100A0B0E9 /* Resources */ = { 338 | isa = PBXResourcesBuildPhase; 339 | buildActionMask = 2147483647; 340 | files = ( 341 | ); 342 | runOnlyForDeploymentPostprocessing = 0; 343 | }; 344 | /* End PBXResourcesBuildPhase section */ 345 | 346 | /* Begin PBXSourcesBuildPhase section */ 347 | 043C63DB1D938EE100A0B0E9 /* Sources */ = { 348 | isa = PBXSourcesBuildPhase; 349 | buildActionMask = 2147483647; 350 | files = ( 351 | 043C64221D93A60C00A0B0E9 /* NSDictionary+AvoidCrash.m in Sources */, 352 | 043C64211D93A60C00A0B0E9 /* NSArray+AvoidCrash.m in Sources */, 353 | 043C63EA1D938EE100A0B0E9 /* ViewController.m in Sources */, 354 | F6EBB7B51F271CCB00ED3B15 /* AvoidCrashStubProxy.m in Sources */, 355 | 043C63E71D938EE100A0B0E9 /* AppDelegate.m in Sources */, 356 | 043C63E41D938EE100A0B0E9 /* main.m in Sources */, 357 | 040330221DACD96E00AE5A41 /* NSObject+AvoidCrash.m in Sources */, 358 | 04C3DFD31DA4EED200E18858 /* NSString+AvoidCrash.m in Sources */, 359 | F61CF29C1FF2206D006093D9 /* AvoidCrashPerson.m in Sources */, 360 | 04FEB8FF1DA55E6B00B5647E /* NSMutableString+AvoidCrash.m in Sources */, 361 | 043C64231D93A60C00A0B0E9 /* NSMutableArray+AvoidCrash.m in Sources */, 362 | 04FB61D91DB2361400C079F2 /* NSAttributedString+AvoidCrash.m in Sources */, 363 | 04FB61DC1DB25FE500C079F2 /* NSMutableAttributedString+AvoidCrash.m in Sources */, 364 | F63018CE1F22EFA000F176DF /* Person.m in Sources */, 365 | 043C64241D93A60C00A0B0E9 /* NSMutableDictionary+AvoidCrash.m in Sources */, 366 | 043C64201D93A60C00A0B0E9 /* AvoidCrash.m in Sources */, 367 | ); 368 | runOnlyForDeploymentPostprocessing = 0; 369 | }; 370 | 043C63F41D938EE100A0B0E9 /* Sources */ = { 371 | isa = PBXSourcesBuildPhase; 372 | buildActionMask = 2147483647; 373 | files = ( 374 | 043C63FD1D938EE100A0B0E9 /* AvoidCrashDemoTests.m in Sources */, 375 | ); 376 | runOnlyForDeploymentPostprocessing = 0; 377 | }; 378 | 043C63FF1D938EE100A0B0E9 /* Sources */ = { 379 | isa = PBXSourcesBuildPhase; 380 | buildActionMask = 2147483647; 381 | files = ( 382 | 043C64081D938EE100A0B0E9 /* AvoidCrashDemoUITests.m in Sources */, 383 | ); 384 | runOnlyForDeploymentPostprocessing = 0; 385 | }; 386 | /* End PBXSourcesBuildPhase section */ 387 | 388 | /* Begin PBXTargetDependency section */ 389 | 043C63FA1D938EE100A0B0E9 /* PBXTargetDependency */ = { 390 | isa = PBXTargetDependency; 391 | target = 043C63DE1D938EE100A0B0E9 /* AvoidCrashDemo */; 392 | targetProxy = 043C63F91D938EE100A0B0E9 /* PBXContainerItemProxy */; 393 | }; 394 | 043C64051D938EE100A0B0E9 /* PBXTargetDependency */ = { 395 | isa = PBXTargetDependency; 396 | target = 043C63DE1D938EE100A0B0E9 /* AvoidCrashDemo */; 397 | targetProxy = 043C64041D938EE100A0B0E9 /* PBXContainerItemProxy */; 398 | }; 399 | /* End PBXTargetDependency section */ 400 | 401 | /* Begin PBXVariantGroup section */ 402 | 043C63EB1D938EE100A0B0E9 /* Main.storyboard */ = { 403 | isa = PBXVariantGroup; 404 | children = ( 405 | 043C63EC1D938EE100A0B0E9 /* Base */, 406 | ); 407 | name = Main.storyboard; 408 | sourceTree = ""; 409 | }; 410 | 043C63F01D938EE100A0B0E9 /* LaunchScreen.storyboard */ = { 411 | isa = PBXVariantGroup; 412 | children = ( 413 | 043C63F11D938EE100A0B0E9 /* Base */, 414 | ); 415 | name = LaunchScreen.storyboard; 416 | sourceTree = ""; 417 | }; 418 | /* End PBXVariantGroup section */ 419 | 420 | /* Begin XCBuildConfiguration section */ 421 | 043C640A1D938EE100A0B0E9 /* Debug */ = { 422 | isa = XCBuildConfiguration; 423 | buildSettings = { 424 | ALWAYS_SEARCH_USER_PATHS = NO; 425 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 426 | CLANG_CXX_LIBRARY = "libc++"; 427 | CLANG_ENABLE_MODULES = YES; 428 | CLANG_ENABLE_OBJC_ARC = YES; 429 | CLANG_WARN_BOOL_CONVERSION = YES; 430 | CLANG_WARN_CONSTANT_CONVERSION = YES; 431 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 432 | CLANG_WARN_EMPTY_BODY = YES; 433 | CLANG_WARN_ENUM_CONVERSION = YES; 434 | CLANG_WARN_INT_CONVERSION = YES; 435 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 436 | CLANG_WARN_UNREACHABLE_CODE = YES; 437 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 438 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 439 | COPY_PHASE_STRIP = NO; 440 | DEBUG_INFORMATION_FORMAT = dwarf; 441 | ENABLE_STRICT_OBJC_MSGSEND = YES; 442 | ENABLE_TESTABILITY = YES; 443 | GCC_C_LANGUAGE_STANDARD = gnu99; 444 | GCC_DYNAMIC_NO_PIC = NO; 445 | GCC_NO_COMMON_BLOCKS = YES; 446 | GCC_OPTIMIZATION_LEVEL = 0; 447 | GCC_PREPROCESSOR_DEFINITIONS = ( 448 | "DEBUG=1", 449 | "$(inherited)", 450 | ); 451 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 452 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 453 | GCC_WARN_UNDECLARED_SELECTOR = YES; 454 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 455 | GCC_WARN_UNUSED_FUNCTION = YES; 456 | GCC_WARN_UNUSED_VARIABLE = YES; 457 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 458 | MTL_ENABLE_DEBUG_INFO = YES; 459 | ONLY_ACTIVE_ARCH = YES; 460 | SDKROOT = iphoneos; 461 | TARGETED_DEVICE_FAMILY = "1,2"; 462 | }; 463 | name = Debug; 464 | }; 465 | 043C640B1D938EE100A0B0E9 /* Release */ = { 466 | isa = XCBuildConfiguration; 467 | buildSettings = { 468 | ALWAYS_SEARCH_USER_PATHS = NO; 469 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 470 | CLANG_CXX_LIBRARY = "libc++"; 471 | CLANG_ENABLE_MODULES = YES; 472 | CLANG_ENABLE_OBJC_ARC = YES; 473 | CLANG_WARN_BOOL_CONVERSION = YES; 474 | CLANG_WARN_CONSTANT_CONVERSION = YES; 475 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 476 | CLANG_WARN_EMPTY_BODY = YES; 477 | CLANG_WARN_ENUM_CONVERSION = YES; 478 | CLANG_WARN_INT_CONVERSION = YES; 479 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 480 | CLANG_WARN_UNREACHABLE_CODE = YES; 481 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 482 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 483 | COPY_PHASE_STRIP = NO; 484 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 485 | ENABLE_NS_ASSERTIONS = NO; 486 | ENABLE_STRICT_OBJC_MSGSEND = YES; 487 | GCC_C_LANGUAGE_STANDARD = gnu99; 488 | GCC_NO_COMMON_BLOCKS = YES; 489 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 490 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 491 | GCC_WARN_UNDECLARED_SELECTOR = YES; 492 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 493 | GCC_WARN_UNUSED_FUNCTION = YES; 494 | GCC_WARN_UNUSED_VARIABLE = YES; 495 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 496 | MTL_ENABLE_DEBUG_INFO = NO; 497 | SDKROOT = iphoneos; 498 | TARGETED_DEVICE_FAMILY = "1,2"; 499 | VALIDATE_PRODUCT = YES; 500 | }; 501 | name = Release; 502 | }; 503 | 043C640D1D938EE100A0B0E9 /* Debug */ = { 504 | isa = XCBuildConfiguration; 505 | buildSettings = { 506 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 507 | CODE_SIGN_STYLE = Manual; 508 | DEVELOPMENT_TEAM = H659824MAF; 509 | GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1"; 510 | INFOPLIST_FILE = AvoidCrashDemo/Info.plist; 511 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 512 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 513 | PRODUCT_BUNDLE_IDENTIFIER = chenfanfang.AvoidCrashDemo; 514 | PRODUCT_NAME = "$(TARGET_NAME)"; 515 | PROVISIONING_PROFILE = "44c40cb7-f6cb-443b-8d10-4ea4d6a8a2f6"; 516 | PROVISIONING_PROFILE_SPECIFIER = Wildcard_Public; 517 | }; 518 | name = Debug; 519 | }; 520 | 043C640E1D938EE100A0B0E9 /* Release */ = { 521 | isa = XCBuildConfiguration; 522 | buildSettings = { 523 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 524 | CODE_SIGN_STYLE = Manual; 525 | DEVELOPMENT_TEAM = ""; 526 | GCC_PREPROCESSOR_DEFINITIONS = ""; 527 | INFOPLIST_FILE = AvoidCrashDemo/Info.plist; 528 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 529 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 530 | PRODUCT_BUNDLE_IDENTIFIER = chenfanfang.AvoidCrashDemo; 531 | PRODUCT_NAME = "$(TARGET_NAME)"; 532 | PROVISIONING_PROFILE_SPECIFIER = ""; 533 | }; 534 | name = Release; 535 | }; 536 | 043C64101D938EE100A0B0E9 /* Debug */ = { 537 | isa = XCBuildConfiguration; 538 | buildSettings = { 539 | BUNDLE_LOADER = "$(TEST_HOST)"; 540 | INFOPLIST_FILE = AvoidCrashDemoTests/Info.plist; 541 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 542 | PRODUCT_BUNDLE_IDENTIFIER = chenfanfang.AvoidCrashDemoTests; 543 | PRODUCT_NAME = "$(TARGET_NAME)"; 544 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AvoidCrashDemo.app/AvoidCrashDemo"; 545 | }; 546 | name = Debug; 547 | }; 548 | 043C64111D938EE100A0B0E9 /* Release */ = { 549 | isa = XCBuildConfiguration; 550 | buildSettings = { 551 | BUNDLE_LOADER = "$(TEST_HOST)"; 552 | INFOPLIST_FILE = AvoidCrashDemoTests/Info.plist; 553 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 554 | PRODUCT_BUNDLE_IDENTIFIER = chenfanfang.AvoidCrashDemoTests; 555 | PRODUCT_NAME = "$(TARGET_NAME)"; 556 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AvoidCrashDemo.app/AvoidCrashDemo"; 557 | }; 558 | name = Release; 559 | }; 560 | 043C64131D938EE100A0B0E9 /* Debug */ = { 561 | isa = XCBuildConfiguration; 562 | buildSettings = { 563 | INFOPLIST_FILE = AvoidCrashDemoUITests/Info.plist; 564 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 565 | PRODUCT_BUNDLE_IDENTIFIER = chenfanfang.AvoidCrashDemoUITests; 566 | PRODUCT_NAME = "$(TARGET_NAME)"; 567 | TEST_TARGET_NAME = AvoidCrashDemo; 568 | USES_XCTRUNNER = YES; 569 | }; 570 | name = Debug; 571 | }; 572 | 043C64141D938EE100A0B0E9 /* Release */ = { 573 | isa = XCBuildConfiguration; 574 | buildSettings = { 575 | INFOPLIST_FILE = AvoidCrashDemoUITests/Info.plist; 576 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 577 | PRODUCT_BUNDLE_IDENTIFIER = chenfanfang.AvoidCrashDemoUITests; 578 | PRODUCT_NAME = "$(TARGET_NAME)"; 579 | TEST_TARGET_NAME = AvoidCrashDemo; 580 | USES_XCTRUNNER = YES; 581 | }; 582 | name = Release; 583 | }; 584 | /* End XCBuildConfiguration section */ 585 | 586 | /* Begin XCConfigurationList section */ 587 | 043C63DA1D938EE100A0B0E9 /* Build configuration list for PBXProject "AvoidCrashDemo" */ = { 588 | isa = XCConfigurationList; 589 | buildConfigurations = ( 590 | 043C640A1D938EE100A0B0E9 /* Debug */, 591 | 043C640B1D938EE100A0B0E9 /* Release */, 592 | ); 593 | defaultConfigurationIsVisible = 0; 594 | defaultConfigurationName = Release; 595 | }; 596 | 043C640C1D938EE100A0B0E9 /* Build configuration list for PBXNativeTarget "AvoidCrashDemo" */ = { 597 | isa = XCConfigurationList; 598 | buildConfigurations = ( 599 | 043C640D1D938EE100A0B0E9 /* Debug */, 600 | 043C640E1D938EE100A0B0E9 /* Release */, 601 | ); 602 | defaultConfigurationIsVisible = 0; 603 | defaultConfigurationName = Release; 604 | }; 605 | 043C640F1D938EE100A0B0E9 /* Build configuration list for PBXNativeTarget "AvoidCrashDemoTests" */ = { 606 | isa = XCConfigurationList; 607 | buildConfigurations = ( 608 | 043C64101D938EE100A0B0E9 /* Debug */, 609 | 043C64111D938EE100A0B0E9 /* Release */, 610 | ); 611 | defaultConfigurationIsVisible = 0; 612 | defaultConfigurationName = Release; 613 | }; 614 | 043C64121D938EE100A0B0E9 /* Build configuration list for PBXNativeTarget "AvoidCrashDemoUITests" */ = { 615 | isa = XCConfigurationList; 616 | buildConfigurations = ( 617 | 043C64131D938EE100A0B0E9 /* Debug */, 618 | 043C64141D938EE100A0B0E9 /* Release */, 619 | ); 620 | defaultConfigurationIsVisible = 0; 621 | defaultConfigurationName = Release; 622 | }; 623 | /* End XCConfigurationList section */ 624 | }; 625 | rootObject = 043C63D71D938EE100A0B0E9 /* Project object */; 626 | } 627 | -------------------------------------------------------------------------------- /AvoidCrashDemo/AvoidCrashDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AvoidCrashDemo/AvoidCrashDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/9/22. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /AvoidCrashDemo/AvoidCrashDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // AvoidCrashDemo 4 | // 5 | // Created by mac on 16/9/22. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | #import "AvoidCrash.h" 12 | #import "NSArray+AvoidCrash.h" 13 | 14 | 15 | @interface AppDelegate () 16 | 17 | @end 18 | 19 | @implementation AppDelegate 20 | 21 | 22 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 23 | 24 | /* 25 | * [AvoidCrash becomeEffective]、[AvoidCrash makeAllEffective] 26 | * 是全局生效。若你只需要部分生效,你可以单个进行处理,比如: 27 | * [NSArray avoidCrashExchangeMethod]; 28 | * [NSMutableArray avoidCrashExchangeMethod]; 29 | * ................. 30 | * ................. 31 | */ 32 | 33 | 34 | 35 | //启动防止崩溃功能(注意区分becomeEffective和makeAllEffective的区别) 36 | //具体区别请看 AvoidCrash.h中的描述 37 | //建议在didFinishLaunchingWithOptions最初始位置调用 上面的方法 38 | 39 | [AvoidCrash makeAllEffective]; 40 | 41 | 42 | //注意:⚠️ 43 | //setupNoneSelClassStringsArr:和setupNoneSelClassStringPrefixsArr: 44 | //可以同时配合使用 45 | 46 | 47 | 48 | //============================================= 49 | // 1、unrecognized selector sent to instance 50 | //============================================= 51 | 52 | //若出现unrecognized selector sent to instance并且控制台输出: 53 | //-[__NSCFConstantString initWithName:age:height:weight:]: unrecognized selector sent to instance 54 | //你可以将@"__NSCFConstantString"添加到如下数组中,当然,你也可以将它的父类添加到下面数组中 55 | //比如,对于部分字符串,继承关系如下 56 | //__NSCFConstantString --> __NSCFString --> NSMutableString --> NSString 57 | //你可以将上面四个类随意一个添加到下面的数组中,建议直接填入 NSString 58 | 59 | NSArray *noneSelClassStrings = @[ 60 | @"NSString" 61 | ]; 62 | [AvoidCrash setupNoneSelClassStringsArr:noneSelClassStrings]; 63 | 64 | 65 | //============================================= 66 | // 2、unrecognized selector sent to instance 67 | //============================================= 68 | 69 | //若需要防止某个前缀的类的unrecognized selector sent to instance 70 | //比如AvoidCrashPerson 71 | //你可以调用如下方法 72 | NSArray *noneSelClassPrefix = @[ 73 | @"AvoidCrash" 74 | ]; 75 | [AvoidCrash setupNoneSelClassStringPrefixsArr:noneSelClassPrefix]; 76 | 77 | 78 | 79 | //监听通知:AvoidCrashNotification, 获取AvoidCrash捕获的崩溃日志的详细信息 80 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dealwithCrashMessage:) name:AvoidCrashNotification object:nil]; 81 | return YES; 82 | } 83 | 84 | 85 | 86 | 87 | - (void)dealwithCrashMessage:(NSNotification *)note { 88 | //不论在哪个线程中导致的crash,这里都是在主线程 89 | 90 | //注意:所有的信息都在userInfo中 91 | //你可以在这里收集相应的崩溃信息进行相应的处理(比如传到自己服务器) 92 | //详细讲解请查看 https://github.com/chenfanfang/AvoidCrash 93 | } 94 | 95 | 96 | @end 97 | -------------------------------------------------------------------------------- /AvoidCrashDemo/AvoidCrashDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /AvoidCrashDemo/AvoidCrashDemo/AvoidCrashPerson.h: -------------------------------------------------------------------------------- 1 | // 2 | // AvoidCrashPerson.h 3 | // AvoidCrashDemo 4 | // 5 | // Created by 陈蕃坊 on 2017/12/26. 6 | // Copyright © 2017年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AvoidCrashPerson : NSObject 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /AvoidCrashDemo/AvoidCrashDemo/AvoidCrashPerson.m: -------------------------------------------------------------------------------- 1 | // 2 | // AvoidCrashPerson.m 3 | // AvoidCrashDemo 4 | // 5 | // Created by 陈蕃坊 on 2017/12/26. 6 | // Copyright © 2017年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import "AvoidCrashPerson.h" 10 | 11 | @implementation AvoidCrashPerson 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /AvoidCrashDemo/AvoidCrashDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /AvoidCrashDemo/AvoidCrashDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /AvoidCrashDemo/AvoidCrashDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /AvoidCrashDemo/AvoidCrashDemo/Person.h: -------------------------------------------------------------------------------- 1 | // 2 | // Person.h 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by chenfanfang on 2017/7/22. 6 | // Copyright © 2017年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //================================================== 12 | // 本类的作用是用来测试unrecoganized selector的处理情况 13 | //================================================== 14 | @interface Person : NSObject 15 | 16 | - (instancetype)initWithName:(NSString *)name age:(NSInteger)age height:(float)height weight:(float)weight; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /AvoidCrashDemo/AvoidCrashDemo/Person.m: -------------------------------------------------------------------------------- 1 | // 2 | // Person.m 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by chenfanfang on 2017/7/22. 6 | // Copyright © 2017年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import "Person.h" 10 | 11 | @implementation Person 12 | 13 | - (instancetype)initWithName:(NSString *)name age:(NSInteger)age height:(float)height weight:(float)weight { 14 | return self; 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /AvoidCrashDemo/AvoidCrashDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/9/22. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /AvoidCrashDemo/AvoidCrashDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // https://github.com/chenfanfang/AvoidCrash 4 | // 5 | // Created by mac on 16/9/22. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | #import "Person.h" 12 | #import "AvoidCrashPerson.h" 13 | 14 | @interface ViewController () 15 | 16 | 17 | @end 18 | 19 | @implementation ViewController 20 | 21 | - (void)viewDidLoad { 22 | [super viewDidLoad]; 23 | 24 | [self executeAllTestMethod]; 25 | 26 | 27 | } 28 | 29 | 30 | //================================================================= 31 | // NSArray_Test 32 | //================================================================= 33 | #pragma mark - NSArray_Test 34 | 35 | - (void)NSArray_Test_InstanceArray { 36 | NSString *nilStr = nil; 37 | NSArray *array = @[@"chenfanfang", nilStr, @"iOSDeveloper"]; 38 | NSLog(@"%@",array); 39 | } 40 | 41 | - (void)NSArray_Test_ObjectAtIndex { 42 | NSArray *arr = @[@"chenfanfang", @"iOS_Dev"]; 43 | NSObject *object = arr[100]; 44 | NSLog(@"object = %@",object); 45 | } 46 | 47 | - (void)NSArray_Test_objectsAtIndexes { 48 | NSArray *array = @[@"chenfanfang",@"iOS"]; 49 | 50 | NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:100]; 51 | [array objectsAtIndexes:indexSet]; 52 | 53 | } 54 | 55 | - (void)NSArray_Test_getObjectsRange { 56 | 57 | NSArray *array = @[@"1", @"2", @"3"];//__NSArrayI 58 | 59 | //NSArray *array = @[@"1"];//__NSSingleObjectArrayI 60 | 61 | //NSArray *array = @[];//NSArray 62 | 63 | NSRange range = NSMakeRange(0, 11); 64 | __unsafe_unretained id cArray[range.length]; 65 | 66 | 67 | [array getObjects:cArray range:range]; 68 | 69 | } 70 | 71 | 72 | //================================================================= 73 | // NSMutableArray_Test 74 | //================================================================= 75 | #pragma mark - NSMutableArray_Test 76 | 77 | - (void)NSMutableArray_Test_ObjectAtIndex { 78 | NSMutableArray *array = @[@"chenfanfang"].mutableCopy; 79 | NSObject *object = array[2]; 80 | //NSObject *object = [array objectAtIndex:20]; 81 | NSLog(@"object = %@",object); 82 | } 83 | 84 | - (void)NSMutableArray_Test_SetObjectAtIndex { 85 | NSMutableArray *array = @[@"chenfanfang"].mutableCopy; 86 | array[3] = @"iOS"; 87 | } 88 | 89 | - (void)NSMutableArray_Test_RemoveObjectAtIndex { 90 | NSMutableArray *array = @[@"chenfanfang", @"iOSDeveloper"].mutableCopy; 91 | [array removeObjectAtIndex:5]; 92 | } 93 | 94 | - (void)NSMutableArray_Test_InsertObjectAtIndex { 95 | 96 | NSMutableArray *array = @[@"chenfanfang"].mutableCopy; 97 | 98 | //test1 beyond bounds 99 | [array insertObject:@"cool" atIndex:5]; 100 | 101 | 102 | //test2 insert nil obj 103 | //[array insertObject:nil atIndex:0]; 104 | 105 | 106 | //test3 insert nil obj 107 | //NSString *nilStr = nil; 108 | //[array addObject:nilStr]; //其本质是调用insertObject: 109 | } 110 | 111 | - (void)NSMutableArray_Test_GetObjectsRange { 112 | NSMutableArray *array = @[@"chenfanfang", @"iOSDeveloper"].mutableCopy; 113 | 114 | NSRange range = NSMakeRange(0, 11); 115 | __unsafe_unretained id cArray[range.length]; 116 | 117 | 118 | [array getObjects:cArray range:range]; 119 | } 120 | 121 | //================================================================= 122 | // NSDictionary_Test 123 | //================================================================= 124 | #pragma mark - NSDictionary_Test 125 | 126 | - (void)NSDictionary_Test_InstanceDictionary { 127 | NSString *nilStr = nil; 128 | NSDictionary *dict = @{ 129 | @"name" : @"chenfanfang", 130 | @"age" : nilStr 131 | }; 132 | NSLog(@"%@",dict); 133 | } 134 | 135 | //================================================================= 136 | // NSMutableDictionary_Test 137 | //================================================================= 138 | #pragma mark - NSMutableDictionary_Test 139 | 140 | 141 | - (void)NSMutableDictionary_Test_SetObjectForKey_1 { 142 | 143 | NSMutableDictionary *dict = @{ 144 | @"name" : @"chenfanfang" 145 | 146 | }.mutableCopy; 147 | NSString *ageKey = nil; 148 | dict[ageKey] = @(25); 149 | NSLog(@"%@",dict); 150 | } 151 | 152 | - (void)NSMutableDictionary_Test_SetObjectForKey_2 { 153 | 154 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 155 | NSString *ageKey = nil; 156 | [dict setObject:@(25) forKey:ageKey]; 157 | NSLog(@"%@",dict); 158 | } 159 | 160 | 161 | 162 | - (void)NSMutableDictionary_Test_RemoveObjectForKey { 163 | 164 | NSMutableDictionary *dict = @{ 165 | @"name" : @"chenfanfang", 166 | @"age" : @(25) 167 | 168 | }.mutableCopy; 169 | NSString *key = nil; 170 | [dict removeObjectForKey:key]; 171 | 172 | NSLog(@"%@",dict); 173 | } 174 | 175 | 176 | //================================================================= 177 | // NSString_Test 178 | //================================================================= 179 | #pragma mark - NSString_Test 180 | 181 | - (void)NSString_Test_CharacterAtIndex { 182 | NSString *str = @"chenfanfang"; 183 | 184 | unichar characteristic = [str characterAtIndex:100]; 185 | NSLog(@"--%c--",characteristic); 186 | } 187 | 188 | - (void)NSString_Test_SubstringFromIndex { 189 | NSString *str = @"chenfanfang"; 190 | 191 | NSString *subStr = [str substringFromIndex:100]; 192 | NSLog(@"%@",subStr); 193 | } 194 | 195 | - (void)NSString_Test_SubstringToIndex { 196 | NSString *str = @"chenfanfang"; 197 | 198 | NSString *subStr = [str substringToIndex:100]; 199 | NSLog(@"%@",subStr); 200 | } 201 | 202 | - (void)NSString_Test_SubstringWithRange { 203 | NSString *str = @"chenfanfang"; 204 | 205 | NSRange range = NSMakeRange(0, 100); 206 | NSString *subStr = [str substringWithRange:range]; 207 | NSLog(@"%@",subStr); 208 | } 209 | 210 | - (void)NSString_Test_StringByReplacingOccurrencesOfString { 211 | NSString *str = @"chenfanfang"; 212 | 213 | NSString *nilStr = nil; 214 | str = [str stringByReplacingOccurrencesOfString:nilStr withString:nilStr]; 215 | NSLog(@"%@",str); 216 | } 217 | 218 | - (void)NSString_Test_StringByReplacingOccurrencesOfStringRange { 219 | NSString *str = @"chenfanfang"; 220 | 221 | NSRange range = NSMakeRange(0, 1000); 222 | str = [str stringByReplacingOccurrencesOfString:@"chen" withString:@"" options:NSCaseInsensitiveSearch range:range]; 223 | NSLog(@"%@",str); 224 | } 225 | 226 | - (void)NSString_Test_stringByReplacingCharactersInRangeWithString { 227 | NSString *str = @"chenfanfang"; 228 | 229 | NSRange range = NSMakeRange(0, 1000); 230 | str = [str stringByReplacingCharactersInRange:range withString:@"cff"]; 231 | NSLog(@"%@",str); 232 | } 233 | 234 | 235 | //================================================================= 236 | // NSMutableString_Test 237 | //================================================================= 238 | #pragma mark - NSMutableString_Test 239 | 240 | - (void)NSMutableString_Test_ReplaceCharactersInRange { 241 | NSMutableString *strM = [NSMutableString stringWithFormat:@"chenfanfang"]; 242 | NSRange range = NSMakeRange(0, 1000); 243 | [strM replaceCharactersInRange:range withString:@"--"]; 244 | } 245 | 246 | - (void)NSMutableString_Test_InsertStringAtIndex{ 247 | NSMutableString *strM = [NSMutableString stringWithFormat:@"chenfanfang"]; 248 | [strM insertString:@"cool" atIndex:1000]; 249 | } 250 | 251 | 252 | - (void)NSMutableString_TestDeleteCharactersInRange{ 253 | NSMutableString *strM = [NSMutableString stringWithFormat:@"chenfanfang"]; 254 | NSRange range = NSMakeRange(0, 1000); 255 | [strM deleteCharactersInRange:range]; 256 | } 257 | 258 | //================================================================= 259 | // NSAttributedString_Test 260 | //================================================================= 261 | #pragma mark - NSAttributedString_Test 262 | 263 | - (void)NSAttributedString_Test_InitWithString { 264 | NSString *str = nil; 265 | NSAttributedString *attributeStr = [[NSAttributedString alloc] initWithString:str]; 266 | NSLog(@"%@",attributeStr); 267 | } 268 | 269 | - (void)NSAttributedString_Test_InitWithAttributedString { 270 | NSAttributedString *nilAttributedStr = nil; 271 | NSAttributedString *attributedStr = [[NSAttributedString alloc] initWithAttributedString:nilAttributedStr]; 272 | NSLog(@"%@",attributedStr); 273 | 274 | 275 | } 276 | 277 | - (void)NSAttributedString_Test_InitWithStringAttributes { 278 | NSDictionary *attributes = @{ 279 | NSForegroundColorAttributeName : [UIColor redColor] 280 | }; 281 | NSString *nilStr = nil; 282 | NSAttributedString *attributedStr = [[NSAttributedString alloc] initWithString:nilStr attributes:attributes]; 283 | NSLog(@"%@",attributedStr); 284 | } 285 | 286 | //================================================================= 287 | // NSMutableAttributedString_Test 288 | //================================================================= 289 | #pragma mark - NSMutableAttributedString_Test 290 | 291 | - (void)NSMutableAttributedString_Test_InitWithString { 292 | 293 | NSString *nilStr = nil; 294 | NSMutableAttributedString *attrStrM = [[NSMutableAttributedString alloc] initWithString:nilStr]; 295 | NSLog(@"%@",attrStrM); 296 | } 297 | 298 | - (void)NSMutableAttributedString_Test_InitWithStringAttributes { 299 | 300 | NSDictionary *attributes = @{ 301 | NSForegroundColorAttributeName : [UIColor redColor] 302 | }; 303 | NSString *nilStr = nil; 304 | NSMutableAttributedString *attrStrM = [[NSMutableAttributedString alloc] initWithString:nilStr attributes:attributes]; 305 | NSLog(@"%@",attrStrM); 306 | } 307 | 308 | 309 | 310 | //================================================================= 311 | // KVC 312 | //================================================================= 313 | #pragma mark - KVC 314 | 315 | 316 | - (void)KVC_Test_SetValueForKey { 317 | //创建一个任意的对象 318 | UITableView *anyObject = [UITableView new]; 319 | [anyObject setValue:self forKey:@"AvoidCrash"]; 320 | 321 | } 322 | 323 | - (void)KVC_Test_SetValueforKeyPath { 324 | UITableView *anyObject = [UITableView new]; 325 | [anyObject setValue:self forKey:@"AvoidCrash"]; 326 | } 327 | 328 | 329 | - (void)KVC_Test_SetValuesForKeysWithDictionary { 330 | //创建一个任意的对象 331 | UITableView *anyObject = [UITableView new]; 332 | NSDictionary *dictionary = @{ 333 | @"name" : @"chenfanfang" 334 | }; 335 | 336 | [anyObject setValuesForKeysWithDictionary:dictionary]; 337 | } 338 | 339 | 340 | //================================================================= 341 | // unrecognized selector sent to instance 342 | //================================================================= 343 | #pragma mark - unrecognized selector sent to instance 344 | /** 345 | 测试没有selector的crash 346 | */ 347 | - (void)testNoSelectorCrash { 348 | 349 | id person1 = @"chenfanfang"; 350 | person1 = [person1 initWithName:@"cff" age:26 height:170 weight:110]; 351 | 352 | } 353 | 354 | - (void)testNoSelectorCrash2 { 355 | id person = [AvoidCrashPerson new]; 356 | [person objectForKey:@"key"]; 357 | } 358 | 359 | //================================================================= 360 | // 执行所有test的方法 361 | //================================================================= 362 | #pragma mark - 执行所有test的方法 363 | 364 | - (void)executeAllTestMethod { 365 | [self NSArray_Test_InstanceArray]; 366 | [self NSArray_Test_ObjectAtIndex]; 367 | [self NSArray_Test_objectsAtIndexes]; 368 | [self NSArray_Test_getObjectsRange]; 369 | 370 | 371 | [self NSMutableArray_Test_ObjectAtIndex]; 372 | [self NSMutableArray_Test_SetObjectAtIndex]; 373 | [self NSMutableArray_Test_RemoveObjectAtIndex]; 374 | [self NSMutableArray_Test_InsertObjectAtIndex]; 375 | [self NSMutableArray_Test_GetObjectsRange]; 376 | 377 | 378 | [self NSDictionary_Test_InstanceDictionary]; 379 | [self NSMutableDictionary_Test_SetObjectForKey_1]; 380 | [self NSMutableDictionary_Test_SetObjectForKey_2]; 381 | [self NSMutableDictionary_Test_RemoveObjectForKey]; 382 | 383 | 384 | [self NSString_Test_CharacterAtIndex]; 385 | [self NSString_Test_SubstringFromIndex]; 386 | [self NSString_Test_SubstringToIndex]; 387 | [self NSString_Test_SubstringWithRange]; 388 | [self NSString_Test_StringByReplacingOccurrencesOfString]; 389 | [self NSString_Test_StringByReplacingOccurrencesOfStringRange]; 390 | [self NSString_Test_stringByReplacingCharactersInRangeWithString]; 391 | 392 | 393 | [self NSMutableString_Test_ReplaceCharactersInRange]; 394 | [self NSMutableString_Test_InsertStringAtIndex]; 395 | [self NSMutableString_TestDeleteCharactersInRange]; 396 | 397 | 398 | [self NSAttributedString_Test_InitWithString]; 399 | [self NSAttributedString_Test_InitWithAttributedString]; 400 | [self NSAttributedString_Test_InitWithStringAttributes]; 401 | 402 | 403 | [self NSMutableAttributedString_Test_InitWithString]; 404 | [self NSMutableAttributedString_Test_InitWithStringAttributes]; 405 | 406 | 407 | [self KVC_Test_SetValueForKey]; 408 | [self KVC_Test_SetValueforKeyPath]; 409 | [self KVC_Test_SetValuesForKeysWithDictionary]; 410 | 411 | 412 | [self testNoSelectorCrash]; 413 | [self testNoSelectorCrash2]; 414 | } 415 | 416 | 417 | 418 | 419 | @end 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | -------------------------------------------------------------------------------- /AvoidCrashDemo/AvoidCrashDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // AvoidCrashDemo 4 | // 5 | // Created by mac on 16/9/22. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /AvoidCrashDemo/AvoidCrashDemoTests/AvoidCrashDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // AvoidCrashDemoTests.m 3 | // AvoidCrashDemoTests 4 | // 5 | // Created by mac on 16/9/22. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AvoidCrashDemoTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation AvoidCrashDemoTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /AvoidCrashDemo/AvoidCrashDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /AvoidCrashDemo/AvoidCrashDemoUITests/AvoidCrashDemoUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // AvoidCrashDemoUITests.m 3 | // AvoidCrashDemoUITests 4 | // 5 | // Created by mac on 16/9/22. 6 | // Copyright © 2016年 chenfanfang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AvoidCrashDemoUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation AvoidCrashDemoUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /AvoidCrashDemo/AvoidCrashDemoUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /AvoidCrashDemo/Screenshot/Leaks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenfanfang/AvoidCrash/1af97337f100c0d9110258449c55c877526d05e0/AvoidCrashDemo/Screenshot/Leaks.png -------------------------------------------------------------------------------- /AvoidCrashDemo/Screenshot/MIT.svg: -------------------------------------------------------------------------------- 1 | licenselicenseMITMIT -------------------------------------------------------------------------------- /AvoidCrashDemo/Screenshot/platform.svg: -------------------------------------------------------------------------------- 1 | platformplatformiosios -------------------------------------------------------------------------------- /AvoidCrashDemo/Screenshot/userInfo信息结构.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenfanfang/AvoidCrash/1af97337f100c0d9110258449c55c877526d05e0/AvoidCrashDemo/Screenshot/userInfo信息结构.png -------------------------------------------------------------------------------- /AvoidCrashDemo/Screenshot/userInfo详细信息.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenfanfang/AvoidCrash/1af97337f100c0d9110258449c55c877526d05e0/AvoidCrashDemo/Screenshot/userInfo详细信息.png -------------------------------------------------------------------------------- /AvoidCrashDemo/Screenshot/崩溃截图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenfanfang/AvoidCrash/1af97337f100c0d9110258449c55c877526d05e0/AvoidCrashDemo/Screenshot/崩溃截图.png -------------------------------------------------------------------------------- /AvoidCrashDemo/Screenshot/视频课程/MJ_课程2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenfanfang/AvoidCrash/1af97337f100c0d9110258449c55c877526d05e0/AvoidCrashDemo/Screenshot/视频课程/MJ_课程2.jpeg -------------------------------------------------------------------------------- /AvoidCrashDemo/Screenshot/视频课程/iOS开发高手课.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenfanfang/AvoidCrash/1af97337f100c0d9110258449c55c877526d05e0/AvoidCrashDemo/Screenshot/视频课程/iOS开发高手课.jpeg -------------------------------------------------------------------------------- /AvoidCrashDemo/Screenshot/配置mutableArray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenfanfang/AvoidCrash/1af97337f100c0d9110258449c55c877526d05e0/AvoidCrashDemo/Screenshot/配置mutableArray.png -------------------------------------------------------------------------------- /AvoidCrashDemo/Screenshot/防止崩溃的输出日志.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenfanfang/AvoidCrash/1af97337f100c0d9110258449c55c877526d05e0/AvoidCrashDemo/Screenshot/防止崩溃的输出日志.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 陈蕃坊 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #### 停更说明 2 | 3 | >由于作者工作时间的问题,目前作者已经暂时停止维护AvoidCrash,已经有多个系统版本没有兼容,大家可以根据自己项目所需要进行改造。 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | ``` 12 | 建议大家只使用 13 | ``` 14 | 15 | 16 | ``` 17 | 18 | NSArray *noneSelClassStrings = @[ 19 | @"NSNull", 20 | @"NSNumber", 21 | @"NSString", 22 | @"NSDictionary", 23 | @"NSArray" 24 | ]; 25 | [AvoidCrash setupNoneSelClassStringsArr:noneSelClassStrings]; 26 | ``` 27 | 不建议大家使用前缀的方式来处理 28 | 29 | [![license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/chenfanfang/AvoidCrash) [![pod](https://img.shields.io/badge/pod-2.5.2-yellow.svg)](https://github.com/chenfanfang/AvoidCrash) [![platform](https://img.shields.io/badge/platform-iOS-ff69b4.svg)](https://github.com/chenfanfang/AvoidCrash) [![aboutme](https://img.shields.io/badge/about%20me-chenfanfang-blue.svg)](http://www.jianshu.com/users/80fadb71940d/latest_articles) 30 | 31 | 疑惑解答 32 | === 33 | 很多开发小伙伴经常私信问我一些问题: 34 | > 1、若集成了腾讯Bugly或者友盟等等异常搜集的SDK,AvoidCrash会影响到它们的异常搜集吗? 35 | 36 | 37 | > 2、为什么集成了AvoidCrash还是会报unrecognized selector sent to instance的异常? 38 | 39 | 关于疑惑的解答,请点击[AvoidCrash疑惑解答](http://www.jianshu.com/p/2b90aa96c0a0) 40 | 41 | 42 | 前言 43 | === 44 | 一个已经发布到AppStore上的App,最忌讳的就是崩溃问题。为什么在开发阶段或者测试阶段都不会崩溃,而发布到AppStore上就崩溃了呢?究其根源,最主要的原因就是数据的错乱。特别是 服务器返回数据的错乱,将严重影响到我们的App。 45 | 46 | 47 | 48 | --- 49 | Foundation框架存在许多潜在崩溃的危险 50 | === 51 | - 将 nil 插入可变数组中会导致崩溃。 52 | - 数组越界会导致崩溃。 53 | - 根据key给字典某个元素重新赋值时,若key为 nil 会导致崩溃。 54 | - ...... 55 | 56 | --- 57 | 58 | AvoidCrash简介 59 | === 60 | - 这个框架利用runtime技术对一些常用并且容易导致崩溃的方法进行处理,可以有效的防止崩溃。 61 | - 并且打印出具体是哪个方法会导致崩溃,让你快速定位导致崩溃的代码。 62 | - 你可以获取到原本导致崩溃的主要信息<由于这个框架的存在,并不会崩溃>,进行相应的处理。比如: 63 | - 你可以将这些崩溃信息发送到自己服务器。 64 | - 你若集成了第三方崩溃日志收集的SDK,比如你用了腾讯的Bugly,你可以上报自定义异常。 65 | - 或许你会问就算防止了崩溃,但是所获取到的数据变成nil或者并非是你所需要的数据,这又有什么用?对于防止崩溃,我的理解是,宁愿一个功能不能用,都要让app活着,至少其他功能还能用。 66 | 67 | --- 68 | 下面先来看下防止崩溃的效果吧 69 | === 70 | 71 | `可导致崩溃的代码` 72 | ``` 73 | NSString *nilStr = nil; 74 |     NSArray *array = @[@"chenfanfang", nilStr]; 75 | ``` 76 | 77 | - 若没有AvoidCrash来防止崩溃,则会直接崩溃,如下图 78 | 79 | ![崩溃截图.png](https://raw.githubusercontent.com/chenfanfang/AvoidCrash/66b631627443490776f964d5f6cdc0d9215d7b09/AvoidCrashDemo/Screenshot/%E5%B4%A9%E6%BA%83%E6%88%AA%E5%9B%BE.png) 80 | 81 | 82 | - 若有AvoidCrash来防止崩溃,则不会崩溃,并且会将原本会崩溃情况的详细信息打印出来,如下图 83 | 84 | ![防止崩溃输出日志.png](https://raw.githubusercontent.com/chenfanfang/AvoidCrash/66b631627443490776f964d5f6cdc0d9215d7b09/AvoidCrashDemo/Screenshot/%E9%98%B2%E6%AD%A2%E5%B4%A9%E6%BA%83%E7%9A%84%E8%BE%93%E5%87%BA%E6%97%A5%E5%BF%97.png) 85 | 86 | 87 | --- 88 | 89 | ## Installation【安装】 90 | 91 | ### From CocoaPods【使用CocoaPods】 92 | 93 | ```ruby 94 | pod 'AvoidCrash', '~> 2.5.2' 95 | ``` 96 | 97 | ### Manually【手动导入】 98 | - Drag all source files under floder `AvoidCrash` to your project.【将`AvoidCrash`文件夹中的所有源代码拽入项目中】 99 | - 对 NSMutableArray+AvoidCrash.m 文件进行 -fno-objc-arc 设置(若使用CocoaPods集成则无需手动配置),配置过程如下图: 100 | 101 | 102 | ![](https://raw.githubusercontent.com/chenfanfang/AvoidCrash/e955af927c5ed57f783a71eaca19cb3f028377d0/AvoidCrashDemo/Screenshot/%E9%85%8D%E7%BD%AEmutableArray.png) 103 | 104 | 105 | 106 | --- 107 | 108 | 109 | 使用方法 110 | === 111 | 112 | 113 | 114 | - AvoidCrash使用注意点讲解 115 | ``` 116 | //让AvoidCrash生效方法有两个becomeEffective和makeAllEffective,若都不调用,则AvoidCrash就不起作用 117 | [AvoidCrash becomeEffective]; //【默认不开启 对”unrecognized selector sent to instance”防止崩溃的处理】 118 | 119 | //若要开启对对”unrecognized selector sent to instance”防止崩溃的处理】,请使用 120 | //[AvoidCrash makeAllEffective],使用注意点,请看AvoidCrash.h中的描述,必须配合[AvoidCrash setupNoneSelClassStringsArr:]的使用 121 | //【建议在didFinishLaunchingWithOptions最初始位置调用】[AvoidCrash makeAllEffective] 122 | 123 | /* 124 | [AvoidCrash becomeEffective]和[AvoidCrash makeAllEffective]是全局生效。若你只需要部分生效,你可以单个进行处理,比如: 125 | [NSArray avoidCrashExchangeMethod]; 126 | [NSMutableArray avoidCrashExchangeMethod]; 127 | ................. 128 | ................. 129 | */ 130 | ``` 131 | 132 | - 在AppDelegate的didFinishLaunchingWithOptions方法中的最初始位置添加如下代码,让AvoidCrash生效 133 | 134 | 135 | ``` 136 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 137 | 138 | //启动防止崩溃功能(注意区分becomeEffective和makeAllEffective的区别) 139 | //具体区别请看 AvoidCrash.h中的描述 140 | //建议在didFinishLaunchingWithOptions最初始位置调用 上面的方法 141 | 142 | [AvoidCrash makeAllEffective]; 143 | 144 | //若出现unrecognized selector sent to instance导致的崩溃并且控制台输出: 145 | //-[__NSCFConstantString initWithName:age:height:weight:]: unrecognized selector sent to instance 146 | //你可以将@"__NSCFConstantString"添加到如下数组中,当然,你也可以将它的父类添加到下面数组中 147 | //比如,对于部分字符串,继承关系如下 148 | //__NSCFConstantString --> __NSCFString --> NSMutableString --> NSString 149 | //你可以将上面四个类随意一个添加到下面的数组中,建议直接填入 NSString 150 | NSArray *noneSelClassStrings = @[ 151 | @"NSString" 152 | ]; 153 | [AvoidCrash setupNoneSelClassStringsArr:noneSelClassStrings]; 154 | 155 | 156 | //监听通知:AvoidCrashNotification, 获取AvoidCrash捕获的崩溃日志的详细信息 157 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dealwithCrashMessage:) name:AvoidCrashNotification object:nil]; 158 | return YES; 159 | } 160 | ``` 161 | 162 | - 若你想要获取崩溃日志的所有详细信息,只需添加通知的监听,监听的通知名为:AvoidCrashNotification 163 | 164 | ``` 165 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 166 |      167 |     [AvoidCrash becomeEffective]; 168 |      169 |     //监听通知:AvoidCrashNotification, 获取AvoidCrash捕获的崩溃日志的详细信息 170 |     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dealwithCrashMessage:) name:AvoidCrashNotification object:nil]; 171 |     return YES; 172 | } 173 | 174 | - (void)dealwithCrashMessage:(NSNotification *)note { 175 | //注意:所有的信息都在userInfo中 176 | //你可以在这里收集相应的崩溃信息进行相应的处理(比如传到自己服务器) 177 |     NSLog(@"%@",note.userInfo); 178 | } 179 | ``` 180 | 181 | - 下面通过打断点的形式来看下userInfo中的信息结构,看下包含了哪些信息 182 | 183 | ![userInfo信息结构.png](https://raw.githubusercontent.com/chenfanfang/AvoidCrash/66b631627443490776f964d5f6cdc0d9215d7b09/AvoidCrashDemo/Screenshot/userInfo%E4%BF%A1%E6%81%AF%E7%BB%93%E6%9E%84.png) 184 | 185 | - 再看下控制台输出日志来看下userInfo中的包含了哪些信息 186 | 187 | ![userInfo详细信息](https://raw.githubusercontent.com/chenfanfang/AvoidCrash/556cab1b9fa25c8265dd1e8a19c816db20e93c24/AvoidCrashDemo/Screenshot/userInfo%E8%AF%A6%E7%BB%86%E4%BF%A1%E6%81%AF.png) 188 | 189 | 190 | 191 | --- 192 | 193 | 目前可以防止崩溃的方法有 194 | === 195 | --- 196 | 197 | 198 | - unrecognized selector sent to instance 199 | - `1. 对”unrecognized selector sent to instance”防止崩溃的处理` 200 | 201 | --- 202 | 203 | - NSArray 204 | - `1. NSArray的快速创建方式 NSArray *array = @[@"chenfanfang", @"AvoidCrash"]; //这种创建方式其实调用的是2中的方法` 205 | - `2. +(instancetype)arrayWithObjects:(const id  _Nonnull __unsafe_unretained *)objects count:(NSUInteger)cnt` 206 | 207 | - `3. 通过下标获取元素 array[100]、[array objectAtIndex:100]` 208 | - `- (id)objectAtIndex:(NSUInteger)index` 209 | 210 | - `4. - (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes` 211 | - `5. - (void)getObjects:(__unsafe_unretained id _Nonnull *)objects range:(NSRange)range` 212 | 213 | --- 214 | 215 | - NSMutableArray 216 | - `1. 通过下标获取元素 array[100]、[array objectAtIndex:100] ` 217 | - `- (id)objectAtIndex:(NSUInteger)index` 218 | - `2. - (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx` 219 | - `3. - (void)removeObjectAtIndex:(NSUInteger)index` 220 | - `4. - (void)insertObject:(id)anObject atIndex:(NSUInteger)index` 221 | - `5. - (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes` 222 | - `6. - (void)getObjects:(__unsafe_unretained id _Nonnull *)objects range:(NSRange)range` 223 | 224 | --- 225 | 226 | - NSDictionary 227 | - `1. NSDictionary的快速创建方式 NSDictionary *dict = @{@"frameWork" : @"AvoidCrash"}; //这种创建方式其实调用的是2中的方法` 228 | - `2. +(instancetype)dictionaryWithObjects:(const id _Nonnull __unsafe_unretained *)objects forKeys:(const id _Nonnull __unsafe_unretained *)keys count:(NSUInteger)cnt` 229 | 230 | --- 231 | 232 | 233 | - NSMutableDictionary 234 | - `1. - (void)setObject:(id)anObject forKey:(id)aKey` 235 | - `2. - (void)removeObjectForKey:(id)aKey` 236 | 237 | 238 | 239 | --- 240 | 241 | 242 | - NSString 243 | - `1. - (unichar)characterAtIndex:(NSUInteger)index` 244 | - `2. - (NSString *)substringFromIndex:(NSUInteger)from` 245 | - `3. - (NSString *)substringToIndex:(NSUInteger)to {` 246 | - `4. - (NSString *)substringWithRange:(NSRange)range {` 247 | - `5. - (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement` 248 | - `6. - (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement options:(NSStringCompareOptions)options range:(NSRange)searchRange` 249 | - `7. - (NSString *)stringByReplacingCharactersInRange:(NSRange)range withString:(NSString *)replacement` 250 | 251 | --- 252 | 253 | 254 | - NSMutableString 255 | - `1. 由于NSMutableString是继承于NSString,所以这里和NSString有些同样的方法就不重复写了` 256 | - `2. - (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)aString` 257 | - `3. - (void)insertString:(NSString *)aString atIndex:(NSUInteger)loc` 258 | - `4. - (void)deleteCharactersInRange:(NSRange)range` 259 | 260 | 261 | --- 262 | 263 | 264 | - KVC 265 | - `1.- (void)setValue:(id)value forKey:(NSString *)key` 266 | - `2.- (void)setValue:(id)value forKeyPath:(NSString *)keyPath` 267 | - `3.- (void)setValue:(id)value forUndefinedKey:(NSString *)key //这个方法一般用来重写,不会主动调用` 268 | - `4.- (void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues` 269 | 270 | --- 271 | 272 | - NSAttributedString 273 | - `1.- (instancetype)initWithString:(NSString *)str` 274 | - `2.- (instancetype)initWithAttributedString:(NSAttributedString *)attrStr` 275 | - `3.- (instancetype)initWithString:(NSString *)str attributes:(NSDictionary *)attrs` 276 | 277 | --- 278 | 279 | 280 | - NSMutableAttributedString 281 | - `1.- (instancetype)initWithString:(NSString *)str` 282 | - `2.- (instancetype)initWithString:(NSString *)str attributes:(NSDictionary *)attrs` 283 | 284 | 285 | 更新 286 | === 287 | 288 | #### 2018-03-14 (pod 2.5.2) 289 | - Fix bug #45 #46 #51 (NSMutableDictionary Set nil Object will Crash.) 290 | 291 | 292 | #### 2017-12-26 (pod 2.5.1) 293 | - 兼容iOS11的处理 294 | 295 | #### 2017-08-11 296 | - 优化对”unrecognized selector sent to instance”防止崩溃的处理 297 | 298 | #### 2017-07-25 299 | - 优化对”unrecognized selector sent to instance”防止崩溃的处理 300 | 301 | 302 | #### 2017-07-23 303 | - 增加对”unrecognized selector sent to instance”防止崩溃的处理 304 | 305 | --- 306 | 307 | #### 2016-12-19 308 | - Release环境下取消控制台的输出。 309 | 310 | 311 | --- 312 | 313 | #### 2016-12-1 314 | - 处理数组的类簇问题,提高兼容性,不论是由于array[100]方式,还是[array objectAtIndex:100]方式 获取数组中的某个元素操作不当而导致的crash,都能被拦截防止崩溃。 315 | - 上一个版本只能防止array[100]导致的崩溃,不能防止[array objectAtIndex:100]导致的崩溃。 316 | 317 | - 统一对线程进行处理,监听通知AvoidCrashNotification后,不论是在主线程导致的crash还是在子线程导致的crash,监听通知的方法统一在"主线程"中。 318 | - 上一个版本中,在哪个线程导致的crash, 则监听通知的方法就在哪个线程中。 319 | 320 | - 新增防止崩溃 (NSArray、NSMutableArray) `- (void)getObjects:(__unsafe_unretained id _Nonnull *)objects range:(NSRange)range` 321 | 322 | 323 | --- 324 | 325 | #### 2016-11-29 326 | - 修复在键盘弹出状态下,按Home键进入后台会导致崩溃的bug。 327 | - 新增防止崩溃(NSArray、NSMutableArray) `- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes` 328 | 329 | --- 330 | 331 | 332 | 333 | #### 2016-10-15 334 | - 修复上一个版本部分方法不能拦截崩溃的BUG,具体修复哪些可以查看issues和简书上的留言。 335 | - 优化崩溃代码的定位,定位崩溃代码更加准确。 336 | - 增加对KVC赋值防止崩溃的处理。 337 | - 增加对NSAttributedString防止崩溃的处理 338 | - 增加对NSMutableAttributedString防止崩溃的处理 339 | 340 | --- 341 | 342 | 343 | 344 | 提示 345 | === 346 | - 1、由于@try @catch的原因,如果防止了你项目中将要crash的代码,有些方法将导致些许的内存泄漏。若你的代码不会导致crash,当然就不存在内存泄漏的问题,crash和些许内存泄漏的选择当然取决于你自己。目前发现的内存泄漏的方法如下图所示,没有显示在下图中的方法,不论是否会导致crash,都不会有内存泄漏。 347 | 348 | ![](https://raw.githubusercontent.com/chenfanfang/AvoidCrash/fdad9c8808559c0b20c8672b2cb6e901d4e4f006/AvoidCrashDemo/Screenshot/Leaks.png) 349 | 350 | - 2、有朋友提出,AvoidCraah和[RegexKitLite](https://github.com/wezm/RegexKitLite)有冲突,毕竟代码不在同一个时代上的(RegexKitLite最后一次提交时在2011年)。同时也说明AvoidCrash的健壮性不够,大家若有什么意见可以提出。 351 | 352 | 期待 353 | === 354 | * 如果你发现了哪些常用的Foundation中的方法存在潜在崩溃的危险,而这个框架中没有进行处理,希望你能 issue, 或者在简书私信我,我将这些方法也添加到AvoidCrash中。谢谢 355 | * 如果你在使用过程中遇到BUG,希望你能 issue, 或者在简书私信我。谢谢(或者尝试下载最新的框架代码看看BUG修复没有) 356 | * 毕竟一个人的能力有限,时间有限,希望有能力的你可以加入到这个项目中来,一起完善AvoidCrash。请Pull Requests我。 357 | 358 | 359 | 360 | 361 | [About me -- 简书](http://www.jianshu.com/users/80fadb71940d/latest_articles) 362 | === 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | --------------------------------------------------------------------------------