├── FJAvoidCrashMechanism.podspec ├── FJAvoidCrashMechanism ├── NSArray+Safe.h ├── NSArray+Safe.m ├── NSAttributedString+Safe.h ├── NSAttributedString+Safe.m ├── NSDictionary+Safe.h ├── NSDictionary+Safe.m ├── NSMutableArray+Safe.h ├── NSMutableArray+Safe.m ├── NSMutableAttributedString+Safe.h ├── NSMutableAttributedString+Safe.m ├── NSMutableDictionary+Safe.h ├── NSMutableDictionary+Safe.m ├── NSMutableString+Safe.h ├── NSMutableString+Safe.m ├── NSObject+Swizzling.h ├── NSObject+Swizzling.m ├── NSString+Safe.h └── NSString+Safe.m ├── FJ_Safe.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ ├── fangjinfeng.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ └── fjf.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ ├── fangjinfeng.xcuserdatad │ └── xcschemes │ │ └── xcschememanagement.plist │ └── fjf.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── FJ_Safe.xcscheme │ └── xcschememanagement.plist ├── FJ_Safe ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── ViewController.h ├── ViewController.m └── main.m ├── FJ_SafeTests ├── FJ_SafeTests.m └── Info.plist ├── FJ_SafeUITests ├── FJ_SafeUITests.m └── Info.plist ├── LICENSE └── README.md /FJAvoidCrashMechanism.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "FJAvoidCrashMechanism" 3 | s.version = "1.0.4" 4 | s.summary = "通过runtime,来防止数组、字典、字符串引起的崩溃" 5 | s.homepage = "http://www.jianshu.com/p/bea2bfed3f3f" 6 | s.license = { :type => 'MIT', :file => 'LICENSE' } 7 | s.author = { 'fangjinfeng' => '116418179@qq.com' } 8 | s.platform = :ios, '7.0' 9 | s.ios.deployment_target = '7.0' 10 | s.source = { :git => "https://github.com/fangjinfeng/FJ_Safe.git", :tag => "1.0.4" } 11 | s.source_files = "FJAvoidCrashMechanism", "*.{h,m}" 12 | s.requires_arc = true 13 | s.framework = 'UIKit' 14 | end 15 | -------------------------------------------------------------------------------- /FJAvoidCrashMechanism/NSArray+Safe.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+Extension.h 3 | // fjTestProject 4 | // 5 | // Created by fjf on 2017/1/3. 6 | // Copyright © 2017年 fjf. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSArray (Safe) 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /FJAvoidCrashMechanism/NSArray+Safe.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+Extension.m 3 | // fjTestProject 4 | // 5 | // Created by fjf on 2017/1/3. 6 | // Copyright © 2017年 fjf. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "NSArray+Safe.h" 11 | #import "NSObject+Swizzling.h" 12 | 13 | @implementation NSArray (Safe) 14 | 15 | #pragma mark -------------------------- Init Methods 16 | 17 | + (void)load { 18 | //只执行一次这个方法 19 | static dispatch_once_t onceToken; 20 | dispatch_once(&onceToken, ^{ 21 | 22 | //替换 objectAtIndex 23 | NSString *tmpStr = @"objectAtIndex:"; 24 | NSString *tmpFirstStr = @"safe_ZeroObjectAtIndex:"; 25 | NSString *tmpThreeStr = @"safe_objectAtIndex:"; 26 | NSString *tmpSecondStr = @"safe_singleObjectAtIndex:"; 27 | 28 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSArray0") 29 | originalSelector:NSSelectorFromString(tmpStr) swizzledSelector:NSSelectorFromString(tmpFirstStr)]; 30 | 31 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSSingleObjectArrayI") 32 | originalSelector:NSSelectorFromString(tmpStr) swizzledSelector:NSSelectorFromString(tmpSecondStr)]; 33 | 34 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSArrayI") 35 | originalSelector:NSSelectorFromString(tmpStr) swizzledSelector:NSSelectorFromString(tmpThreeStr)]; 36 | 37 | // 替换 objectAtIndexedSubscript 38 | 39 | NSString *tmpSubscriptStr = @"objectAtIndexedSubscript:"; 40 | NSString *tmpSecondSubscriptStr = @"safe_objectAtIndexedSubscript:"; 41 | 42 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSArrayI") 43 | originalSelector:NSSelectorFromString(tmpSubscriptStr) swizzledSelector:NSSelectorFromString(tmpSecondSubscriptStr)]; 44 | 45 | // 替换 arrayWithObjects:count: 46 | NSString *tmpFirstArrayWithObjectsStr = @"arrayWithObjects:count:"; 47 | NSString *tmpSecondArrayWithObjectsStr = @"safe_arrayWithObjects:count:"; 48 | 49 | 50 | [NSObject fjf_exchangeClassMethodWithSelfClass:[self class] 51 | originalSelector:NSSelectorFromString(tmpFirstArrayWithObjectsStr) swizzledSelector:NSSelectorFromString(tmpSecondArrayWithObjectsStr)]; 52 | 53 | // 替换 objectsAtIndexes 54 | NSString *tmpFirstObjectsAtIndexesStr = @"objectsAtIndexes:"; 55 | NSString *tmpSecondObjectsAtIndexesStr = @"safe_objectsAtIndexes:"; 56 | 57 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"NSArray") 58 | originalSelector:NSSelectorFromString(tmpFirstObjectsAtIndexesStr) swizzledSelector:NSSelectorFromString(tmpSecondObjectsAtIndexesStr)]; 59 | 60 | // 替换 getObjects:range: 61 | 62 | NSString *tmpFirstGetObjectsRangeStr = @"getObjects:range:"; 63 | NSString *tmpSecondGetObjectsRangeStr = @"safe_arrayGetObjects:range:"; 64 | NSString *tmpThreeGetObjectsRangeStr = @"safe_singleObjectArrayGetObjects:range:"; 65 | NSString *tmpFourGetObjectsRangeStr = @"safe_arrayIGetObjects:range:"; 66 | 67 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"NSArray") 68 | originalSelector:NSSelectorFromString(tmpFirstGetObjectsRangeStr) swizzledSelector:NSSelectorFromString(tmpSecondGetObjectsRangeStr)]; 69 | 70 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSSingleObjectArrayI") 71 | originalSelector:NSSelectorFromString(tmpFirstGetObjectsRangeStr) swizzledSelector:NSSelectorFromString(tmpThreeGetObjectsRangeStr)]; 72 | 73 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSArrayI") 74 | originalSelector:NSSelectorFromString(tmpFirstGetObjectsRangeStr) swizzledSelector:NSSelectorFromString(tmpFourGetObjectsRangeStr)]; 75 | 76 | 77 | 78 | 79 | }); 80 | 81 | } 82 | 83 | 84 | 85 | 86 | #pragma mark -------------------------- Exchange Method 87 | 88 | #pragma mark --- objectAtIndex 89 | 90 | /** 91 | 取出NSArray 第index个 值 对应 __NSArrayI 92 | 93 | @param index 索引 index 94 | @return 返回值 95 | */ 96 | - (id)safe_objectAtIndex:(NSUInteger)index { 97 | if (index >= self.count){ 98 | return nil; 99 | } 100 | return [self safe_objectAtIndex:index]; 101 | } 102 | 103 | 104 | /** 105 | 取出NSArray 第index个 值 对应 __NSSingleObjectArrayI 106 | 107 | @param index 索引 index 108 | @return 返回值 109 | */ 110 | - (id)safe_singleObjectAtIndex:(NSUInteger)index { 111 | if (index >= self.count){ 112 | return nil; 113 | } 114 | return [self safe_singleObjectAtIndex:index]; 115 | } 116 | 117 | /** 118 | 取出NSArray 第index个 值 对应 __NSArray0 119 | 120 | @param index 索引 index 121 | @return 返回值 122 | */ 123 | - (id)safe_ZeroObjectAtIndex:(NSUInteger)index { 124 | if (index >= self.count){ 125 | return nil; 126 | } 127 | return [self safe_ZeroObjectAtIndex:index]; 128 | } 129 | 130 | #pragma mark --- objectAtIndexedSubscript 131 | /** 132 | 取出NSArray 第index个 值 对应 __NSArrayI 133 | 134 | @param idx 索引 idx 135 | @return 返回值 136 | */ 137 | - (id)safe_objectAtIndexedSubscript:(NSUInteger)idx { 138 | if (idx >= self.count){ 139 | return nil; 140 | } 141 | return [self safe_objectAtIndexedSubscript:idx]; 142 | } 143 | 144 | 145 | 146 | #pragma mark --- objectsAtIndexes 147 | 148 | /** 149 | 取出NSArray 150 | 151 | @param indexes 索引范围 152 | @return 返回数组 153 | */ 154 | - (NSArray *)safe_objectsAtIndexes:(NSIndexSet *)indexes { 155 | __block BOOL beyondLimit = NO; 156 | [indexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) { 157 | if (idx > self.count) { 158 | *stop = YES; 159 | beyondLimit = YES; 160 | } 161 | }]; 162 | if (beyondLimit) { 163 | return nil; 164 | } 165 | return [self safe_objectsAtIndexes:indexes]; 166 | } 167 | 168 | 169 | #pragma mark --- ArrayWithObjects: count: 170 | /** 171 | 初始化方法 172 | 173 | @param objects 数组 174 | @param cnt 数量 175 | @return 数组 176 | */ 177 | + (instancetype)safe_arrayWithObjects:(const id _Nonnull __unsafe_unretained *)objects count:(NSUInteger)cnt { 178 | 179 | id instance = nil; 180 | @try { 181 | instance = [self safe_arrayWithObjects:objects count:cnt]; 182 | } 183 | @catch (NSException *exception) { 184 | 185 | //以下是对错误数据的处理,把为nil的数据去掉,然后初始化数组 186 | NSInteger newObjsIndex = 0; 187 | id _Nonnull __unsafe_unretained newObjects[cnt]; 188 | 189 | for (int i = 0; i < cnt; i++) { 190 | if (objects[i] != nil) { 191 | newObjects[newObjsIndex] = objects[i]; 192 | newObjsIndex++; 193 | } 194 | } 195 | instance = [self safe_arrayWithObjects:newObjects count:newObjsIndex]; 196 | } 197 | @finally { 198 | return instance; 199 | } 200 | } 201 | 202 | 203 | #pragma mark --- getObjects:range: 204 | 205 | //NSArray getObjects:range: 206 | - (void)safe_arrayGetObjects:(__unsafe_unretained id _Nonnull *)objects range:(NSRange)range { 207 | if (range.location > self.count) { 208 | return; 209 | } 210 | 211 | if (range.length > self.count) { 212 | return; 213 | } 214 | 215 | if ((range.location + range.length) > self.count) { 216 | return; 217 | } 218 | 219 | return [self safe_arrayGetObjects:objects range:range]; 220 | } 221 | 222 | // __NSSingleObjectArrayI safe_singleObjectArrayGetObjects:range: 223 | - (void)safe_singleObjectArrayGetObjects:(__unsafe_unretained id _Nonnull *)objects range:(NSRange)range { 224 | if (range.location > self.count) { 225 | return; 226 | } 227 | 228 | if (range.length > self.count) { 229 | return; 230 | } 231 | 232 | if ((range.location + range.length) > self.count) { 233 | return; 234 | } 235 | 236 | return [self safe_arrayGetObjects:objects range:range]; 237 | } 238 | 239 | //__NSArrayI safe_arrayIGetObjects:range: 240 | - (void)safe_arrayIGetObjects:(__unsafe_unretained id _Nonnull *)objects range:(NSRange)range { 241 | if (range.location > self.count) { 242 | return; 243 | } 244 | 245 | if (range.length > self.count) { 246 | return; 247 | } 248 | 249 | if ((range.location + range.length) > self.count) { 250 | return; 251 | } 252 | 253 | return [self safe_arrayGetObjects:objects range:range]; 254 | } 255 | @end 256 | -------------------------------------------------------------------------------- /FJAvoidCrashMechanism/NSAttributedString+Safe.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSAttributedString+Safe.h 3 | // FJ_Safe 4 | // 5 | // Created by 方金峰 on 2018/10/23. 6 | // Copyright © 2018年 fjf. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NSAttributedString (Safe) 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /FJAvoidCrashMechanism/NSAttributedString+Safe.m: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // NSAttributedString+Safe.m 4 | // FJ_Safe 5 | // 6 | // Created by 方金峰 on 2018/10/23. 7 | // Copyright © 2018年 fjf. All rights reserved. 8 | // 9 | 10 | #import "NSObject+Swizzling.h" 11 | #import "NSAttributedString+Safe.h" 12 | 13 | @implementation NSAttributedString (Safe) 14 | #pragma mark -------------------------- Init Methods 15 | 16 | + (void)load { 17 | //只执行一次这个方法 18 | static dispatch_once_t onceToken; 19 | dispatch_once(&onceToken, ^{ 20 | 21 | // 替换 initWithString: 22 | NSString *tmpStr = @"initWithString:"; 23 | NSString *tmpSafeStr = @"safe_initWithString:"; 24 | 25 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"NSConcreteAttributedString") 26 | originalSelector:NSSelectorFromString(tmpStr) swizzledSelector:NSSelectorFromString(tmpSafeStr)]; 27 | 28 | 29 | // 替换 initWithAttributedString 30 | NSString *tmpAttributedStr = @"initWithAttributedString:"; 31 | NSString *tmpSafeAttributedStr = @"safe_initWithAttributedString:"; 32 | 33 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"NSConcreteAttributedString") 34 | originalSelector:NSSelectorFromString(tmpAttributedStr) swizzledSelector:NSSelectorFromString(tmpSafeAttributedStr)]; 35 | 36 | 37 | // 替换 initWithString:attributes: 38 | 39 | NSString *tmpInitAttributedsStr = @"initWithString:attributes:"; 40 | NSString *tmpSafeInitAttributedsStr = @"safe_initWithString:attributes:"; 41 | 42 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"NSConcreteAttributedString") 43 | originalSelector:NSSelectorFromString(tmpInitAttributedsStr) swizzledSelector:NSSelectorFromString(tmpSafeInitAttributedsStr)]; 44 | 45 | 46 | }); 47 | 48 | } 49 | 50 | #pragma mark -------------------------- Exchange Methods 51 | #pragma mark - initWithString: 52 | 53 | - (instancetype)safe_initWithString:(NSString *)str { 54 | 55 | id object = nil; 56 | 57 | @try { 58 | object = [self safe_initWithString:str]; 59 | } 60 | @catch (NSException *exception) { 61 | 62 | } 63 | @finally { 64 | return object; 65 | } 66 | } 67 | 68 | 69 | //================================================================= 70 | // initWithAttributedString 71 | //================================================================= 72 | #pragma mark - initWithAttributedString 73 | 74 | - (instancetype)safe_initWithAttributedString:(NSAttributedString *)attrStr { 75 | id object = nil; 76 | 77 | @try { 78 | object = [self safe_initWithAttributedString:attrStr]; 79 | } 80 | @catch (NSException *exception) { 81 | 82 | } 83 | @finally { 84 | return object; 85 | } 86 | } 87 | 88 | 89 | //================================================================= 90 | // initWithString:attributes: 91 | //================================================================= 92 | #pragma mark - initWithString:attributes: 93 | 94 | - (instancetype)safe_initWithString:(NSString *)str attributes:(NSDictionary *)attrs { 95 | id object = nil; 96 | 97 | @try { 98 | object = [self safe_initWithString:str attributes:attrs]; 99 | } 100 | @catch (NSException *exception) { 101 | 102 | } 103 | @finally { 104 | return object; 105 | } 106 | } 107 | @end 108 | -------------------------------------------------------------------------------- /FJAvoidCrashMechanism/NSDictionary+Safe.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSDictionary+Safe.h 3 | // FJ_Safe 4 | // 5 | // Created by 方金峰 on 2018/10/23. 6 | // Copyright © 2018年 fjf. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NSDictionary (Safe) 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /FJAvoidCrashMechanism/NSDictionary+Safe.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSDictionary+Safe.m 3 | // FJ_Safe 4 | // 5 | // Created by 方金峰 on 2018/10/23. 6 | // Copyright © 2018年 fjf. All rights reserved. 7 | // 8 | 9 | #import "NSDictionary+Safe.h" 10 | #import "NSObject+Swizzling.h" 11 | 12 | @implementation NSDictionary (Safe) 13 | #pragma mark -------------------------- Init Methods 14 | 15 | + (void)load { 16 | //只执行一次这个方法 17 | static dispatch_once_t onceToken; 18 | dispatch_once(&onceToken, ^{ 19 | 20 | // 替换 removeObjectForKey: 21 | NSString *tmpRemoveStr = @"dictionaryWithObjects:forKeys:count:"; 22 | NSString *tmpSafeRemoveStr = @"safe_dictionaryWithObjects:forKeys:count:"; 23 | 24 | [NSObject fjf_exchangeClassMethodWithSelfClass:[self class] 25 | originalSelector:NSSelectorFromString(tmpRemoveStr) swizzledSelector:NSSelectorFromString(tmpSafeRemoveStr)]; 26 | 27 | 28 | 29 | }); 30 | 31 | } 32 | 33 | 34 | #pragma mark -------------------------- Exchange Methods 35 | 36 | + (instancetype)safe_dictionaryWithObjects:(const id _Nonnull __unsafe_unretained *)objects forKeys:(const id _Nonnull __unsafe_unretained *)keys count:(NSUInteger)cnt { 37 | id instance = nil; 38 | 39 | @try { 40 | instance = [self safe_dictionaryWithObjects:objects forKeys:keys count:cnt]; 41 | } 42 | @catch (NSException *exception) { 43 | 44 | //处理错误的数据,然后重新初始化一个字典 45 | NSUInteger index = 0; 46 | id _Nonnull __unsafe_unretained newObjects[cnt]; 47 | id _Nonnull __unsafe_unretained newkeys[cnt]; 48 | 49 | for (int i = 0; i < cnt; i++) { 50 | if (objects[i] && keys[i]) { 51 | newObjects[index] = objects[i]; 52 | newkeys[index] = keys[i]; 53 | index++; 54 | } 55 | } 56 | instance = [self safe_dictionaryWithObjects:newObjects forKeys:newkeys count:index]; 57 | } 58 | @finally { 59 | return instance; 60 | } 61 | } 62 | @end 63 | -------------------------------------------------------------------------------- /FJAvoidCrashMechanism/NSMutableArray+Safe.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableArray+Extension.h 3 | // fjTestProject 4 | // 5 | // Created by fjf on 2017/1/3. 6 | // Copyright © 2017年 fjf. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSMutableArray (Safe) 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /FJAvoidCrashMechanism/NSMutableArray+Safe.m: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // NSMutableArray+Extension.m 4 | // fjTestProject 5 | // 6 | // Created by fjf on 2017/1/3. 7 | // Copyright © 2017年 fjf. All rights reserved. 8 | // 9 | 10 | #import 11 | #import "NSObject+Swizzling.h" 12 | #import "NSMutableArray+Safe.h" 13 | 14 | 15 | @implementation NSMutableArray (Safe) 16 | 17 | #pragma mark -------------------------- Init Methods 18 | 19 | + (void)load { 20 | //只执行一次这个方法 21 | static dispatch_once_t onceToken; 22 | dispatch_once(&onceToken, ^{ 23 | 24 | //替换 objectAtIndex: 25 | NSString *tmpGetStr = @"objectAtIndex:"; 26 | NSString *tmpSafeGetStr = @"safeMutable_objectAtIndex:"; 27 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSArrayM") 28 | originalSelector:NSSelectorFromString(tmpGetStr) swizzledSelector:NSSelectorFromString(tmpSafeGetStr)]; 29 | 30 | //替换 removeObjectsInRange: 31 | NSString *tmpRemoveStr = @"removeObjectsInRange:"; 32 | NSString *tmpSafeRemoveStr = @"safeMutable_removeObjectsInRange:"; 33 | 34 | 35 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSArrayM") 36 | originalSelector:NSSelectorFromString(tmpRemoveStr) swizzledSelector:NSSelectorFromString(tmpSafeRemoveStr)]; 37 | 38 | 39 | //替换 insertObject:atIndex: 40 | NSString *tmpInsertStr = @"insertObject:atIndex:"; 41 | NSString *tmpSafeInsertStr = @"safeMutable_insertObject:atIndex:"; 42 | 43 | 44 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSArrayM") 45 | originalSelector:NSSelectorFromString(tmpInsertStr) swizzledSelector:NSSelectorFromString(tmpSafeInsertStr)]; 46 | 47 | //替换 removeObject:inRange: 48 | NSString *tmpRemoveRangeStr = @"removeObject:inRange:"; 49 | NSString *tmpSafeRemoveRangeStr = @"safeMutable_removeObject:inRange:"; 50 | 51 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSArrayM") 52 | originalSelector:NSSelectorFromString(tmpRemoveRangeStr) swizzledSelector:NSSelectorFromString(tmpSafeRemoveRangeStr)]; 53 | 54 | 55 | // 替换 objectAtIndexedSubscript 56 | 57 | NSString *tmpSubscriptStr = @"objectAtIndexedSubscript:"; 58 | NSString *tmpSecondSubscriptStr = @"safeMutable_objectAtIndexedSubscript:"; 59 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSArrayM") 60 | originalSelector:NSSelectorFromString(tmpSubscriptStr) swizzledSelector:NSSelectorFromString(tmpSecondSubscriptStr)]; 61 | 62 | // 替换 getObjects:range: 63 | NSString *tmpFirstGetObjectsRangeStr = @"getObjects:range:"; 64 | NSString *tmpSecondGetObjectsRangeStr = @"safeMutable_getObjects:range:"; 65 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSArrayM") 66 | originalSelector:NSSelectorFromString(tmpFirstGetObjectsRangeStr) swizzledSelector:NSSelectorFromString(tmpSecondGetObjectsRangeStr)]; 67 | 68 | // 替换 setObject:atIndexedSubscript: 69 | NSString *tmpFirstSetObjectAtIndexedSubscriptStr = @"setObject:atIndexedSubscript:"; 70 | NSString *tmpSecondSetObjectAtIndexedSubscriptStr = @"safe_setObject:atIndexedSubscript:"; 71 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSArrayM") 72 | originalSelector:NSSelectorFromString(tmpFirstSetObjectAtIndexedSubscriptStr) swizzledSelector:NSSelectorFromString(tmpSecondSetObjectAtIndexedSubscriptStr)]; 73 | }); 74 | 75 | } 76 | 77 | #pragma mark -------------------------- Exchange Methods 78 | 79 | /** 80 | 取出NSArray 第index个 值 81 | 82 | @param index 索引 index 83 | @return 返回值 84 | */ 85 | - (id)safeMutable_objectAtIndex:(NSUInteger)index { 86 | if (index >= self.count){ 87 | return nil; 88 | } 89 | return [self safeMutable_objectAtIndex:index]; 90 | } 91 | 92 | /** 93 | NSMutableArray 移除 索引 index 对应的 值 94 | 95 | @param range 移除 范围 96 | */ 97 | - (void)safeMutable_removeObjectsInRange:(NSRange)range { 98 | 99 | if (range.location > self.count) { 100 | return; 101 | } 102 | 103 | if (range.length > self.count) { 104 | return; 105 | } 106 | 107 | if ((range.location + range.length) > self.count) { 108 | return; 109 | } 110 | 111 | return [self safeMutable_removeObjectsInRange:range]; 112 | } 113 | 114 | 115 | /** 116 | 在range范围内, 移除掉anObject 117 | 118 | @param anObject 移除的anObject 119 | @param range 范围 120 | */ 121 | - (void)safeMutable_removeObject:(id)anObject inRange:(NSRange)range { 122 | if (range.location > self.count) { 123 | return; 124 | } 125 | 126 | if (range.length > self.count) { 127 | return; 128 | } 129 | 130 | if ((range.location + range.length) > self.count) { 131 | return; 132 | } 133 | 134 | if (!anObject){ 135 | return; 136 | } 137 | 138 | 139 | return [self safeMutable_removeObject:anObject inRange:range]; 140 | 141 | } 142 | 143 | /** 144 | NSMutableArray 插入 新值 到 索引index 指定位置 145 | 146 | @param anObject 新值 147 | @param index 索引 index 148 | */ 149 | - (void)safeMutable_insertObject:(id)anObject atIndex:(NSUInteger)index { 150 | if (index > self.count) { 151 | return; 152 | } 153 | 154 | if (!anObject){ 155 | return; 156 | } 157 | 158 | [self safeMutable_insertObject:anObject atIndex:index]; 159 | } 160 | 161 | 162 | /** 163 | 取出NSArray 第index个 值 对应 __NSArrayI 164 | 165 | @param idx 索引 idx 166 | @return 返回值 167 | */ 168 | - (id)safeMutable_objectAtIndexedSubscript:(NSUInteger)idx { 169 | if (idx >= self.count){ 170 | return nil; 171 | } 172 | return [self safeMutable_objectAtIndexedSubscript:idx]; 173 | } 174 | 175 | 176 | /** 177 | 获取range范围数组并赋值给objects 178 | 179 | @param objects objects 180 | @param range 范围 181 | */ 182 | - (void)safeMutable_getObjects:(__unsafe_unretained id _Nonnull *)objects range:(NSRange)range { 183 | if (range.location > self.count) { 184 | return; 185 | } 186 | 187 | if (range.length > self.count) { 188 | return; 189 | } 190 | 191 | if ((range.location + range.length) > self.count) { 192 | return; 193 | } 194 | 195 | return [self safeMutable_getObjects:objects range:range]; 196 | } 197 | 198 | 199 | //================================================================= 200 | // array set object at index 201 | //================================================================= 202 | #pragma mark - get object from array 203 | 204 | 205 | - (void)safe_setObject:(id)obj atIndexedSubscript:(NSUInteger)idx { 206 | 207 | if (idx >= self.count) { 208 | return; 209 | } 210 | 211 | if (!obj) { 212 | return; 213 | } 214 | 215 | return [self safe_setObject:obj atIndexedSubscript:idx]; 216 | } 217 | @end 218 | -------------------------------------------------------------------------------- /FJAvoidCrashMechanism/NSMutableAttributedString+Safe.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableAttributedString+Safe.h 3 | // FJ_Safe 4 | // 5 | // Created by 方金峰 on 2018/10/23. 6 | // Copyright © 2018年 fjf. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NSMutableAttributedString (Safe) 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /FJAvoidCrashMechanism/NSMutableAttributedString+Safe.m: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // NSMutableAttributedString+Safe.m 4 | // FJ_Safe 5 | // 6 | // Created by 方金峰 on 2018/10/23. 7 | // Copyright © 2018年 fjf. All rights reserved. 8 | // 9 | 10 | #import "NSObject+Swizzling.h" 11 | #import "NSMutableAttributedString+Safe.h" 12 | 13 | @implementation NSMutableAttributedString (Safe) 14 | #pragma mark -------------------------- Init Methods 15 | 16 | + (void)load { 17 | //只执行一次这个方法 18 | static dispatch_once_t onceToken; 19 | dispatch_once(&onceToken, ^{ 20 | 21 | // 替换 initWithString: 22 | NSString *tmpStr = @"initWithString:"; 23 | NSString *tmpSafeStr = @"safeMutable_initWithString:"; 24 | 25 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"NSConcreteMutableAttributedString") 26 | originalSelector:NSSelectorFromString(tmpStr) swizzledSelector:NSSelectorFromString(tmpSafeStr)]; 27 | 28 | //替换 initWithString:attributes: 29 | NSString *tmpAttributedStr = @"initWithString:attributes:"; 30 | NSString *tmpSafeAttributedStr = @"safeMutable_initWithString:attributes:"; 31 | 32 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"NSConcreteMutableAttributedString") 33 | originalSelector:NSSelectorFromString(tmpAttributedStr) swizzledSelector:NSSelectorFromString(tmpSafeAttributedStr)]; 34 | 35 | }); 36 | } 37 | 38 | #pragma mark -------------------------- Exchange Methods 39 | 40 | #pragma mark --- initWithString: 41 | 42 | 43 | - (instancetype)safeMutable_initWithString:(NSString *)str { 44 | id object = nil; 45 | 46 | @try { 47 | object = [self safeMutable_initWithString:str]; 48 | } 49 | @catch (NSException *exception) { 50 | } 51 | @finally { 52 | return object; 53 | } 54 | } 55 | 56 | 57 | 58 | #pragma mark --- initWithString:attributes: 59 | 60 | 61 | - (instancetype)safeMutable_initWithString:(NSString *)str attributes:(NSDictionary *)attrs { 62 | id object = nil; 63 | 64 | @try { 65 | object = [self safeMutable_initWithString:str attributes:attrs]; 66 | } 67 | @catch (NSException *exception) { 68 | 69 | } 70 | @finally { 71 | return object; 72 | } 73 | } 74 | @end 75 | -------------------------------------------------------------------------------- /FJAvoidCrashMechanism/NSMutableDictionary+Safe.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableDictionary+Extension.h 3 | // fjTestProject 4 | // 5 | // Created by fjf on 2017/1/5. 6 | // Copyright © 2017年 fjf. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSMutableDictionary (Safe) 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /FJAvoidCrashMechanism/NSMutableDictionary+Safe.m: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // NSMutableDictionary+Extension.m 4 | // fjTestProject 5 | // 6 | // Created by fjf on 2017/1/5. 7 | // Copyright © 2017年 fjf. All rights reserved. 8 | // 9 | 10 | #import 11 | #import "NSObject+Swizzling.h" 12 | #import "NSMutableDictionary+Safe.h" 13 | 14 | @implementation NSMutableDictionary (Safe) 15 | #pragma mark -------------------------- Init Methods 16 | 17 | + (void)load { 18 | //只执行一次这个方法 19 | static dispatch_once_t onceToken; 20 | dispatch_once(&onceToken, ^{ 21 | 22 | // 替换 removeObjectForKey: 23 | NSString *tmpRemoveStr = @"removeObjectForKey:"; 24 | NSString *tmpSafeRemoveStr = @"safeMutable_removeObjectForKey:"; 25 | 26 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSDictionaryM") 27 | originalSelector:NSSelectorFromString(tmpRemoveStr) swizzledSelector:NSSelectorFromString(tmpSafeRemoveStr)]; 28 | 29 | if (@available(iOS 11.0, *)) { 30 | NSString *tmpSetObjectSubStr = @"setObject:forKeyedSubscript:"; 31 | NSString *tmpSafeSetObjectSubStr = @"safe_setObject:forKeyedSubscript:"; 32 | 33 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSDictionaryM") 34 | originalSelector:NSSelectorFromString(tmpSetObjectSubStr) swizzledSelector:NSSelectorFromString(tmpSafeSetObjectSubStr)]; 35 | } 36 | 37 | 38 | // 替换 setObject:forKey: 39 | NSString *tmpSetStr = @"setObject:forKey:"; 40 | NSString *tmpSafeSetRemoveStr = @"safeMutable_setObject:forKey:"; 41 | 42 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSDictionaryM") 43 | originalSelector:NSSelectorFromString(tmpSetStr) swizzledSelector:NSSelectorFromString(tmpSafeSetRemoveStr)]; 44 | 45 | }); 46 | 47 | } 48 | 49 | #pragma mark -------------------------- Exchange Methods 50 | 51 | /** 52 | 根据akey 移除 对应的 键值对 53 | 54 | @param aKey key 55 | */ 56 | - (void)safeMutable_removeObjectForKey:(id)aKey { 57 | if (!aKey) { 58 | return; 59 | } 60 | [self safeMutable_removeObjectForKey:aKey]; 61 | } 62 | 63 | /** 64 | 将键值对 添加 到 NSMutableDictionary 内 65 | 66 | @param anObject 值 67 | @param aKey 键 68 | */ 69 | - (void)safeMutable_setObject:(id)anObject forKey:(id)aKey { 70 | if (!anObject) { 71 | return; 72 | } 73 | if (!aKey) { 74 | return; 75 | } 76 | return [self safeMutable_setObject:anObject forKey:aKey]; 77 | } 78 | 79 | #pragma mark - setObject:forKeyedSubscript: 80 | - (void)safe_setObject:(id)anObject forKeyedSubscript:(id)aKey { 81 | if (!anObject) { 82 | return; 83 | } 84 | if (!aKey) { 85 | return; 86 | } 87 | return [self safe_setObject:anObject forKeyedSubscript:aKey]; 88 | } 89 | @end 90 | -------------------------------------------------------------------------------- /FJAvoidCrashMechanism/NSMutableString+Safe.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableString+Safe.h 3 | // fjTestProject 4 | // 5 | // Created by fjf on 2017/1/5. 6 | // Copyright © 2017年 fjf. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSMutableString (Safe) 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /FJAvoidCrashMechanism/NSMutableString+Safe.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableString+Safe.m 3 | // fjTestProject 4 | // 5 | // Created by fjf on 2017/1/5. 6 | // Copyright © 2017年 fjf. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "NSObject+Swizzling.h" 11 | #import "NSMutableString+Safe.h" 12 | 13 | @implementation NSMutableString (Safe) 14 | 15 | #pragma mark -------------------------- Init Methods 16 | 17 | + (void)load { 18 | //只执行一次这个方法 19 | static dispatch_once_t onceToken; 20 | dispatch_once(&onceToken, ^{ 21 | 22 | // 替换 substringFromIndex: 23 | NSString *tmpSubFromStr = @"substringFromIndex:"; 24 | NSString *tmpSafeSubFromStr = @"safeMutable_substringFromIndex:"; 25 | 26 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSCFString") 27 | originalSelector:NSSelectorFromString(tmpSubFromStr) swizzledSelector:NSSelectorFromString(tmpSafeSubFromStr)]; 28 | 29 | 30 | // 替换 substringToIndex: 31 | NSString *tmpSubToStr = @"substringToIndex:"; 32 | NSString *tmpSafeSubToStr = @"safeMutable_substringToIndex:"; 33 | 34 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSCFString") 35 | originalSelector:NSSelectorFromString(tmpSubToStr) swizzledSelector:NSSelectorFromString(tmpSafeSubToStr)]; 36 | 37 | 38 | // 替换 substringWithRange: 39 | NSString *tmpSubRangeStr = @"substringWithRange:"; 40 | NSString *tmpSafeSubRangeStr = @"safeMutable_substringWithRange:"; 41 | 42 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSCFString") 43 | originalSelector:NSSelectorFromString(tmpSubRangeStr) swizzledSelector:NSSelectorFromString(tmpSafeSubRangeStr)]; 44 | 45 | 46 | 47 | // 替换 rangeOfString:options:range:locale: 48 | NSString *tmpRangeOfStr = @"rangeOfString:options:range:locale:"; 49 | NSString *tmpSafeRangeOfStr = @"safeMutable_rangeOfString:options:range:locale:"; 50 | 51 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSCFString") 52 | originalSelector:NSSelectorFromString(tmpRangeOfStr) swizzledSelector:NSSelectorFromString(tmpSafeRangeOfStr)]; 53 | 54 | 55 | // 替换 appendString 56 | NSString *tmpAppendStr = @"appendString:"; 57 | NSString *tmpSafeAppendStr = @"safeMutable_appendString:"; 58 | 59 | 60 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSCFString") 61 | originalSelector:NSSelectorFromString(tmpAppendStr) swizzledSelector:NSSelectorFromString(tmpSafeAppendStr)]; 62 | 63 | 64 | 65 | // 替换 replaceCharactersInRange 66 | NSString *tmpReplaceCharactersInRangeStr = @"replaceCharactersInRange:withString:"; 67 | NSString *tmpSafeReplaceCharactersInRangeStr = @"safeMutable_replaceCharactersInRange:withString:"; 68 | 69 | 70 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSCFString") 71 | originalSelector:NSSelectorFromString(tmpReplaceCharactersInRangeStr) swizzledSelector:NSSelectorFromString(tmpSafeReplaceCharactersInRangeStr)]; 72 | 73 | 74 | //替换 insertString:atIndex: 75 | NSString *tmpInsertStringStr = @"insertString:atIndex:"; 76 | NSString *tmpSafaInsertStringStr = @"safeMutable_insertString:atIndex:"; 77 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSCFString") 78 | originalSelector:NSSelectorFromString(tmpInsertStringStr) swizzledSelector:NSSelectorFromString(tmpSafaInsertStringStr)]; 79 | 80 | 81 | 82 | //替换 deleteCharactersInRange 83 | NSString *tmpDeleteCharactersInRangeStr = @"deleteCharactersInRange:"; 84 | NSString *tmpSafaDeleteCharactersInRangeStr = @"safeMutable_deleteCharactersInRange:"; 85 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSCFString") 86 | originalSelector:NSSelectorFromString(tmpDeleteCharactersInRangeStr) swizzledSelector:NSSelectorFromString(tmpSafaDeleteCharactersInRangeStr)]; 87 | 88 | 89 | }); 90 | 91 | } 92 | 93 | 94 | #pragma mark -------------------------- Exchange Methods 95 | #pragma mark --- substringFromIndex: 96 | /**************************************** substringFromIndex: ***********************************/ 97 | /** 98 | 从from位置截取字符串 对应 __NSCFString 99 | 100 | @param from 截取起始位置 101 | @return 截取的子字符串 102 | */ 103 | - (NSString *)safeMutable_substringFromIndex:(NSUInteger)from { 104 | if (from > self.length ) { 105 | return nil; 106 | } 107 | return [self safeMutable_substringFromIndex:from]; 108 | } 109 | 110 | 111 | #pragma mark --- substringToIndex: 112 | /**************************************** substringToIndex: ***********************************/ 113 | /** 114 | 从开始截取到to位置的字符串 对应 __NSCFString 115 | 116 | @param to 截取终点位置 117 | @return 返回截取的字符串 118 | */ 119 | - (NSString *)safeMutable_substringToIndex:(NSUInteger)to { 120 | if (to > self.length ) { 121 | return nil; 122 | } 123 | return [self safeMutable_substringToIndex:to]; 124 | } 125 | 126 | 127 | #pragma mark --- rangeOfString:options:range:locale: 128 | /*********************************** rangeOfString:options:range:locale: ***************************/ 129 | /** 130 | 搜索指定 字符串 对应 __NSCFString 131 | 132 | @param searchString 指定 字符串 133 | @param mask 比较模式 134 | @param rangeOfReceiverToSearch 搜索 范围 135 | @param locale 本地化 136 | @return 返回搜索到的字符串 范围 137 | */ 138 | - (NSRange)safeMutable_rangeOfString:(NSString *)searchString options:(NSStringCompareOptions)mask range:(NSRange)rangeOfReceiverToSearch locale:(nullable NSLocale *)locale { 139 | if (!searchString) { 140 | searchString = self; 141 | } 142 | 143 | if (rangeOfReceiverToSearch.location > self.length) { 144 | rangeOfReceiverToSearch = NSMakeRange(0, self.length); 145 | } 146 | 147 | if (rangeOfReceiverToSearch.length > self.length) { 148 | rangeOfReceiverToSearch = NSMakeRange(0, self.length); 149 | } 150 | 151 | if ((rangeOfReceiverToSearch.location + rangeOfReceiverToSearch.length) > self.length) { 152 | rangeOfReceiverToSearch = NSMakeRange(0, self.length); 153 | } 154 | 155 | 156 | return [self safeMutable_rangeOfString:searchString options:mask range:rangeOfReceiverToSearch locale:locale]; 157 | } 158 | 159 | 160 | #pragma mark --- substringWithRange: 161 | /*********************************** substringWithRange: ***************************/ 162 | /** 163 | 截取指定范围的字符串 对应 __NSCFString 164 | 165 | @param range 指定的范围 166 | @return 返回截取的字符串 167 | */ 168 | - (NSString *)safeMutable_substringWithRange:(NSRange)range { 169 | if (range.location > self.length) { 170 | return nil; 171 | } 172 | 173 | if (range.length > self.length) { 174 | return nil; 175 | } 176 | 177 | if ((range.location + range.length) > self.length) { 178 | return nil; 179 | } 180 | return [self safeMutable_substringWithRange:range]; 181 | } 182 | 183 | 184 | #pragma mark --- appendString: 185 | /*********************************** appendString: ***************************/ 186 | /** 187 | 追加字符串 对应 __NSCFString 188 | 189 | @param aString 追加的字符串 190 | */ 191 | - (void)safeMutable_appendString:(NSString *)aString { 192 | if (!aString) { 193 | return; 194 | } 195 | return [self safeMutable_appendString:aString]; 196 | } 197 | 198 | #pragma mark --- replaceCharactersInRange 199 | 200 | - (void)safeMutable_replaceCharactersInRange:(NSRange)range withString:(NSString *)aString { 201 | 202 | if (range.location > self.length) { 203 | return; 204 | } 205 | 206 | if (range.length > self.length) { 207 | return; 208 | } 209 | 210 | if ((range.location + range.length) > self.length) { 211 | return; 212 | } 213 | 214 | if (!aString) { 215 | return; 216 | } 217 | 218 | return [self safeMutable_replaceCharactersInRange:range withString:aString]; 219 | } 220 | 221 | #pragma mark --- insertString:atIndex: 222 | 223 | - (void)safeMutable_insertString:(NSString *)aString atIndex:(NSUInteger)loc { 224 | if (loc > self.length) { 225 | return; 226 | } 227 | return [self safeMutable_insertString:aString atIndex:loc]; 228 | } 229 | 230 | 231 | #pragma mark --- deleteCharactersInRange 232 | 233 | - (void)safeMutable_deleteCharactersInRange:(NSRange)range { 234 | 235 | if (range.location > self.length) { 236 | return; 237 | } 238 | 239 | if (range.length > self.length) { 240 | return; 241 | } 242 | 243 | if ((range.location + range.length) > self.length) { 244 | return; 245 | } 246 | return [self safeMutable_deleteCharactersInRange:range]; 247 | } 248 | 249 | 250 | @end 251 | -------------------------------------------------------------------------------- /FJAvoidCrashMechanism/NSObject+Swizzling.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+Swizzling.h 3 | // FJ_Safe 4 | // 5 | // Created by fjf on 2017/3/13. 6 | // Copyright © 2017年 fjf. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSObject (Swizzling) 12 | 13 | /** 14 | 先判断是否添加方法是否成功,如果成功取代原方法,否则交换实例方法 15 | 16 | @param selfClass 类 17 | @param originalSelector 方法 18 | @param swizzledSelector 交换方法 19 | */ 20 | + (void)fjf_exchangeInstanceMethodWithSelfClass:(Class)selfClass 21 | originalSelector:(SEL)originalSelector 22 | swizzledSelector:(SEL)swizzledSelector; 23 | 24 | /** 25 | 直接 类方法 交换 26 | 27 | @param selfClass 类 28 | @param originalSelector 方法 29 | @param swizzledSelector 交换方法 30 | */ 31 | + (void)fjf_exchangeClassMethodWithSelfClass:(Class)selfClass 32 | originalSelector:(SEL)originalSelector 33 | swizzledSelector:(SEL)swizzledSelector; 34 | @end 35 | -------------------------------------------------------------------------------- /FJAvoidCrashMechanism/NSObject+Swizzling.m: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // NSObject+Swizzling.m 4 | // FJ_Safe 5 | // 6 | // Created by fjf on 2017/3/13. 7 | // Copyright © 2017年 fjf. All rights reserved. 8 | // 9 | 10 | #import 11 | #import "NSObject+Swizzling.h" 12 | 13 | @implementation NSObject (Swizzling) 14 | #pragma mark -------------------------- Public Methods 15 | + (void)fjf_exchangeInstanceMethodWithSelfClass:(Class)selfClass 16 | originalSelector:(SEL)originalSelector 17 | swizzledSelector:(SEL)swizzledSelector { 18 | 19 | Method originalMethod = class_getInstanceMethod(selfClass, originalSelector); 20 | Method swizzledMethod = class_getInstanceMethod(selfClass, swizzledSelector); 21 | BOOL didAddMethod = class_addMethod(selfClass, 22 | originalSelector, 23 | method_getImplementation(swizzledMethod), 24 | method_getTypeEncoding(swizzledMethod)); 25 | if (didAddMethod) { 26 | class_replaceMethod(selfClass, 27 | swizzledSelector, 28 | method_getImplementation(originalMethod), 29 | method_getTypeEncoding(originalMethod)); 30 | } else { 31 | method_exchangeImplementations(originalMethod, swizzledMethod); 32 | } 33 | } 34 | 35 | 36 | + (void)fjf_exchangeClassMethodWithSelfClass:(Class)selfClass 37 | originalSelector:(SEL)originalSelector 38 | swizzledSelector:(SEL)swizzledSelector { 39 | 40 | Method originalMethod = class_getClassMethod(selfClass, originalSelector); 41 | Method swizzledMethod = class_getClassMethod(selfClass, swizzledSelector); 42 | method_exchangeImplementations(originalMethod, swizzledMethod); 43 | } 44 | @end 45 | -------------------------------------------------------------------------------- /FJAvoidCrashMechanism/NSString+Safe.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Extension.h 3 | // fjTestProject 4 | // 5 | // Created by fjf on 2017/1/5. 6 | // Copyright © 2017年 fjf. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSString (Safe) 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /FJAvoidCrashMechanism/NSString+Safe.m: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // NSString+Extension.m 4 | // fjTestProject 5 | // 6 | // Created by fjf on 2017/1/5. 7 | // Copyright © 2017年 fjf. All rights reserved. 8 | // 9 | 10 | #import 11 | #import "NSString+Safe.h" 12 | #import "NSObject+Swizzling.h" 13 | 14 | @implementation NSString (Safe) 15 | 16 | #pragma mark -------------------------- Init Methods 17 | 18 | + (void)load { 19 | //只执行一次这个方法 20 | static dispatch_once_t onceToken; 21 | dispatch_once(&onceToken, ^{ 22 | 23 | // 替换 substringFromIndex: 24 | NSString *tmpSubFromStr = @"substringFromIndex:"; 25 | NSString *tmpSafeSubFromStr = @"safe_substringFromIndex:"; 26 | NSString *tmpSafePointSubFromStr = @"safePoint_substringFromIndex:"; 27 | 28 | 29 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSCFConstantString") 30 | originalSelector:NSSelectorFromString(tmpSubFromStr) swizzledSelector:NSSelectorFromString(tmpSafeSubFromStr)]; 31 | 32 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"NSTaggedPointerString") 33 | originalSelector:NSSelectorFromString(tmpSubFromStr) swizzledSelector:NSSelectorFromString(tmpSafePointSubFromStr)]; 34 | 35 | 36 | 37 | 38 | // 替换 substringToIndex: 39 | NSString *tmpSubToStr = @"substringToIndex:"; 40 | NSString *tmpSafeSubToStr = @"safe_substringToIndex:"; 41 | NSString *tmpSafePointSubToStr = @"safePoint_substringToIndex:"; 42 | 43 | 44 | 45 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSCFConstantString") 46 | originalSelector:NSSelectorFromString(tmpSubToStr) swizzledSelector:NSSelectorFromString(tmpSafeSubToStr)]; 47 | 48 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"NSTaggedPointerString") 49 | originalSelector:NSSelectorFromString(tmpSubToStr) swizzledSelector:NSSelectorFromString(tmpSafePointSubToStr)]; 50 | 51 | 52 | 53 | 54 | // 替换 substringWithRange: 55 | NSString *tmpSubRangeStr = @"substringWithRange:"; 56 | NSString *tmpSafeSubRangeStr = @"safe_substringWithRange:"; 57 | NSString *tmpSafePointSubRangeStr = @"safePoint_substringWithRange:"; 58 | 59 | 60 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSCFConstantString") 61 | originalSelector:NSSelectorFromString(tmpSubRangeStr) swizzledSelector:NSSelectorFromString(tmpSafeSubRangeStr)]; 62 | 63 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"NSTaggedPointerString") 64 | originalSelector:NSSelectorFromString(tmpSubRangeStr) swizzledSelector:NSSelectorFromString(tmpSafePointSubRangeStr)]; 65 | 66 | 67 | 68 | // 替换 rangeOfString:options:range:locale: 69 | NSString *tmpRangeOfStr = @"rangeOfString:options:range:locale:"; 70 | NSString *tmpSafeRangeOfStr = @"safe_rangeOfString:options:range:locale:"; 71 | NSString *tmpSafePointRangeOfStr = @"safePoint_rangeOfString:options:range:locale:"; 72 | 73 | 74 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSCFConstantString") 75 | originalSelector:NSSelectorFromString(tmpRangeOfStr) swizzledSelector:NSSelectorFromString(tmpSafeRangeOfStr)]; 76 | 77 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"NSTaggedPointerString") 78 | originalSelector:NSSelectorFromString(tmpRangeOfStr) swizzledSelector:NSSelectorFromString(tmpSafePointRangeOfStr)]; 79 | 80 | 81 | 82 | // 替换 characterAtIndex: 83 | NSString *tmpCharacterAtIndexStr = @"characterAtIndex:"; 84 | NSString *tmpSafeCharacterAtIndexStr = @"safe_characterAtIndex:"; 85 | NSString *tmpSafePointCharacterAtIndexStr = @"safePoint_characterAtIndex:"; 86 | 87 | 88 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSCFConstantString") 89 | originalSelector:NSSelectorFromString(tmpCharacterAtIndexStr) swizzledSelector:NSSelectorFromString(tmpSafeCharacterAtIndexStr)]; 90 | 91 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"NSTaggedPointerString") 92 | originalSelector:NSSelectorFromString(tmpCharacterAtIndexStr) swizzledSelector:NSSelectorFromString(tmpSafePointCharacterAtIndexStr)]; 93 | 94 | 95 | // 替换 stringByReplacingOccurrencesOfString: 96 | NSString *tmpStringByReplacingOccurrencesOfStringStr = @"stringByReplacingOccurrencesOfString:withString:"; 97 | NSString *tmpSafeStringByReplacingOccurrencesOfStringStr = @"safe_stringByReplacingOccurrencesOfString:withString:"; 98 | NSString *tmpSafePointStringByReplacingOccurrencesOfStringStr = @"safePoint_stringByReplacingOccurrencesOfString:withString:"; 99 | 100 | 101 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSCFConstantString") 102 | originalSelector:NSSelectorFromString(tmpStringByReplacingOccurrencesOfStringStr) swizzledSelector:NSSelectorFromString(tmpSafeStringByReplacingOccurrencesOfStringStr)]; 103 | 104 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"NSTaggedPointerString") 105 | originalSelector:NSSelectorFromString(tmpStringByReplacingOccurrencesOfStringStr) swizzledSelector:NSSelectorFromString(tmpSafePointStringByReplacingOccurrencesOfStringStr)]; 106 | 107 | 108 | 109 | //替换 stringByReplacingOccurrencesOfString:withString:options:range: 110 | 111 | NSString *tmpStringByReplacingOccurrencesOfStringRangeStr = @"stringByReplacingOccurrencesOfString:withString:options:range:"; 112 | NSString *tmpSafeStringByReplacingOccurrencesOfStringRangeStr = @"safe_stringByReplacingOccurrencesOfString:withString:options:range:"; 113 | NSString *tmpSafePointStringByReplacingOccurrencesOfStringRangeStr = @"safePoint_stringByReplacingOccurrencesOfString:withString:options:range:"; 114 | 115 | 116 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSCFConstantString") 117 | originalSelector:NSSelectorFromString(tmpStringByReplacingOccurrencesOfStringRangeStr) swizzledSelector:NSSelectorFromString(tmpSafeStringByReplacingOccurrencesOfStringRangeStr)]; 118 | 119 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"NSTaggedPointerString") 120 | originalSelector:NSSelectorFromString(tmpStringByReplacingOccurrencesOfStringRangeStr) swizzledSelector:NSSelectorFromString(tmpSafePointStringByReplacingOccurrencesOfStringRangeStr)]; 121 | 122 | 123 | // 替换 stringByReplacingCharactersInRange:withString: 124 | 125 | NSString *tmpStringByReplacingCharactersInRangeStr = @"stringByReplacingCharactersInRange:withString:"; 126 | NSString *tmpSafeStringByReplacingCharactersInRangeStr = @"safe_stringByReplacingCharactersInRange:withString:"; 127 | NSString *tmpSafePointStringByReplacingCharactersInRangeStr = @"safePoint_stringByReplacingCharactersInRange:withString:"; 128 | 129 | 130 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"__NSCFConstantString") 131 | originalSelector:NSSelectorFromString(tmpStringByReplacingCharactersInRangeStr) swizzledSelector:NSSelectorFromString(tmpSafeStringByReplacingCharactersInRangeStr)]; 132 | 133 | [NSObject fjf_exchangeInstanceMethodWithSelfClass:NSClassFromString(@"NSTaggedPointerString") 134 | originalSelector:NSSelectorFromString(tmpStringByReplacingCharactersInRangeStr) swizzledSelector:NSSelectorFromString(tmpSafePointStringByReplacingCharactersInRangeStr)]; 135 | 136 | }); 137 | } 138 | 139 | #pragma mark -------------------------- Exchange Methods 140 | 141 | #pragma mark ---- substringFromIndex 142 | /**************************************** substringFromIndex: ***********************************/ 143 | /** 144 | 从from位置截取字符串 对应 __NSCFConstantString 145 | 146 | @param from 截取起始位置 147 | @return 截取的子字符串 148 | */ 149 | - (NSString *)safe_substringFromIndex:(NSUInteger)from { 150 | if (from > self.length ) { 151 | return nil; 152 | } 153 | return [self safe_substringFromIndex:from]; 154 | } 155 | /** 156 | 从from位置截取字符串 对应 NSTaggedPointerString 157 | 158 | @param from 截取起始位置 159 | @return 截取的子字符串 160 | */ 161 | - (NSString *)safePoint_substringFromIndex:(NSUInteger)from { 162 | if (from > self.length ) { 163 | return nil; 164 | } 165 | return [self safePoint_substringFromIndex:from]; 166 | } 167 | 168 | #pragma mark ---- substringToIndex 169 | /**************************************** substringFromIndex: ***********************************/ 170 | /** 171 | 从开始截取到to位置的字符串 对应 __NSCFConstantString 172 | 173 | @param to 截取终点位置 174 | @return 返回截取的字符串 175 | */ 176 | - (NSString *)safe_substringToIndex:(NSUInteger)to { 177 | if (to > self.length ) { 178 | return nil; 179 | } 180 | return [self safe_substringToIndex:to]; 181 | } 182 | 183 | /** 184 | 从开始截取到to位置的字符串 对应 NSTaggedPointerString 185 | 186 | @param to 截取终点位置 187 | @return 返回截取的字符串 188 | */ 189 | - (NSString *)safePoint_substringToIndex:(NSUInteger)to { 190 | if (to > self.length ) { 191 | return nil; 192 | } 193 | return [self safePoint_substringToIndex:to]; 194 | } 195 | 196 | 197 | #pragma mark ---- rangeOfString:options:range:locale: 198 | /*********************************** rangeOfString:options:range:locale: ***************************/ 199 | /** 200 | 搜索指定 字符串 对应 __NSCFConstantString 201 | 202 | @param searchString 指定 字符串 203 | @param mask 比较模式 204 | @param rangeOfReceiverToSearch 搜索 范围 205 | @param locale 本地化 206 | @return 返回搜索到的字符串 范围 207 | */ 208 | - (NSRange)safe_rangeOfString:(NSString *)searchString options:(NSStringCompareOptions)mask range:(NSRange)rangeOfReceiverToSearch locale:(nullable NSLocale *)locale { 209 | if (!searchString) { 210 | searchString = self; 211 | } 212 | 213 | if (rangeOfReceiverToSearch.location > self.length) { 214 | rangeOfReceiverToSearch = NSMakeRange(0, self.length); 215 | } 216 | 217 | if (rangeOfReceiverToSearch.length > self.length) { 218 | rangeOfReceiverToSearch = NSMakeRange(0, self.length); 219 | } 220 | 221 | if ((rangeOfReceiverToSearch.location + rangeOfReceiverToSearch.length) > self.length) { 222 | rangeOfReceiverToSearch = NSMakeRange(0, self.length); 223 | } 224 | 225 | 226 | return [self safe_rangeOfString:searchString options:mask range:rangeOfReceiverToSearch locale:locale]; 227 | } 228 | 229 | 230 | /** 231 | 搜索指定 字符串 对应 NSTaggedPointerString 232 | 233 | @param searchString 指定 字符串 234 | @param mask 比较模式 235 | @param rangeOfReceiverToSearch 搜索 范围 236 | @param locale 本地化 237 | @return 返回搜索到的字符串 范围 238 | */ 239 | - (NSRange)safePoint_rangeOfString:(NSString *)searchString options:(NSStringCompareOptions)mask range:(NSRange)rangeOfReceiverToSearch locale:(nullable NSLocale *)locale { 240 | if (!searchString) { 241 | searchString = self; 242 | } 243 | 244 | if (rangeOfReceiverToSearch.location > self.length) { 245 | rangeOfReceiverToSearch = NSMakeRange(0, self.length); 246 | } 247 | 248 | if (rangeOfReceiverToSearch.length > self.length) { 249 | rangeOfReceiverToSearch = NSMakeRange(0, self.length); 250 | } 251 | 252 | if ((rangeOfReceiverToSearch.location + rangeOfReceiverToSearch.length) > self.length) { 253 | rangeOfReceiverToSearch = NSMakeRange(0, self.length); 254 | } 255 | 256 | 257 | return [self safePoint_rangeOfString:searchString options:mask range:rangeOfReceiverToSearch locale:locale]; 258 | } 259 | 260 | #pragma mark ---- substringWithRange: 261 | /*********************************** substringWithRange: ***************************/ 262 | /** 263 | 截取指定范围的字符串 对应 __NSCFConstantString 264 | 265 | @param range 指定的范围 266 | @return 返回截取的字符串 267 | */ 268 | - (NSString *)safe_substringWithRange:(NSRange)range { 269 | if (range.location > self.length) { 270 | return nil; 271 | } 272 | 273 | if (range.length > self.length) { 274 | return nil; 275 | } 276 | 277 | if ((range.location + range.length) > self.length) { 278 | return nil; 279 | } 280 | return [self safe_substringWithRange:range]; 281 | } 282 | 283 | /** 284 | 截取指定范围的字符串 对应 NSTaggedPointerString 285 | 286 | @param range 指定的范围 287 | @return 返回截取的字符串 288 | */ 289 | - (NSString *)safePoint_substringWithRange:(NSRange)range { 290 | if (range.location > self.length) { 291 | return nil; 292 | } 293 | 294 | if (range.length > self.length) { 295 | return nil; 296 | } 297 | 298 | if ((range.location + range.length) > self.length) { 299 | return nil; 300 | } 301 | return [self safePoint_substringWithRange:range]; 302 | } 303 | 304 | #pragma mark ---- characterAtIndex 305 | 306 | - (unichar)safe_characterAtIndex:(NSUInteger)index { 307 | unichar characteristic; 308 | if (index < self.length) { 309 | characteristic = [self safe_characterAtIndex:index]; 310 | } 311 | 312 | return characteristic; 313 | }; 314 | 315 | - (unichar)safePoint_characterAtIndex:(NSUInteger)index { 316 | unichar characteristic; 317 | if (index < self.length) { 318 | characteristic = [self safePoint_characterAtIndex:index]; 319 | } 320 | 321 | return characteristic; 322 | }; 323 | 324 | #pragma mark ---- stringByReplacingOccurrencesOfString: 325 | 326 | - (NSString *)safe_stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement { 327 | 328 | if (!target) { 329 | return self; 330 | } 331 | 332 | if (!replacement) { 333 | return self; 334 | } 335 | return [self safePoint_stringByReplacingOccurrencesOfString:target withString:replacement]; 336 | } 337 | 338 | - (NSString *)safePoint_stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement { 339 | 340 | if (!target) { 341 | return self; 342 | } 343 | 344 | if (!replacement) { 345 | return self; 346 | } 347 | return [self safePoint_stringByReplacingOccurrencesOfString:target withString:replacement]; 348 | } 349 | 350 | #pragma mark - stringByReplacingOccurrencesOfString:withString:options:range: 351 | 352 | - (NSString *)safe_stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement options:(NSStringCompareOptions)options range:(NSRange)searchRange { 353 | 354 | NSString *newStr = nil; 355 | 356 | @try { 357 | newStr = [self safe_stringByReplacingOccurrencesOfString:target withString:replacement options:options range:searchRange]; 358 | } 359 | @catch (NSException *exception) { 360 | 361 | newStr = nil; 362 | } 363 | @finally { 364 | return newStr; 365 | } 366 | } 367 | 368 | - (NSString *)safePoint_stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement options:(NSStringCompareOptions)options range:(NSRange)searchRange { 369 | 370 | NSString *newStr = nil; 371 | 372 | @try { 373 | newStr = [self safePoint_stringByReplacingOccurrencesOfString:target withString:replacement options:options range:searchRange]; 374 | } 375 | @catch (NSException *exception) { 376 | 377 | newStr = nil; 378 | } 379 | @finally { 380 | return newStr; 381 | } 382 | } 383 | 384 | 385 | //================================================================= 386 | // stringByReplacingCharactersInRange:withString: 387 | //================================================================= 388 | #pragma mark - stringByReplacingCharactersInRange:withString: 389 | 390 | - (NSString *)safe_stringByReplacingCharactersInRange:(NSRange)range withString:(NSString *)replacement { 391 | 392 | 393 | NSString *newStr = nil; 394 | 395 | @try { 396 | newStr = [self safe_stringByReplacingCharactersInRange:range withString:replacement]; 397 | } 398 | @catch (NSException *exception) { 399 | newStr = nil; 400 | } 401 | @finally { 402 | return newStr; 403 | } 404 | } 405 | 406 | - (NSString *)safePoint_stringByReplacingCharactersInRange:(NSRange)range withString:(NSString *)replacement { 407 | 408 | 409 | NSString *newStr = nil; 410 | 411 | @try { 412 | newStr = [self safePoint_stringByReplacingCharactersInRange:range withString:replacement]; 413 | } 414 | @catch (NSException *exception) { 415 | newStr = nil; 416 | } 417 | @finally { 418 | return newStr; 419 | } 420 | } 421 | @end 422 | -------------------------------------------------------------------------------- /FJ_Safe.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 30426B3F1E1E7D430077F3A8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 30426B3E1E1E7D430077F3A8 /* main.m */; }; 11 | 30426B421E1E7D430077F3A8 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 30426B411E1E7D430077F3A8 /* AppDelegate.m */; }; 12 | 30426B451E1E7D430077F3A8 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 30426B441E1E7D430077F3A8 /* ViewController.m */; }; 13 | 30426B481E1E7D430077F3A8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 30426B461E1E7D430077F3A8 /* Main.storyboard */; }; 14 | 30426B4A1E1E7D430077F3A8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 30426B491E1E7D430077F3A8 /* Assets.xcassets */; }; 15 | 30426B4D1E1E7D430077F3A8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 30426B4B1E1E7D430077F3A8 /* LaunchScreen.storyboard */; }; 16 | 30426B581E1E7D430077F3A8 /* FJ_SafeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 30426B571E1E7D430077F3A8 /* FJ_SafeTests.m */; }; 17 | 30426B631E1E7D430077F3A8 /* FJ_SafeUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 30426B621E1E7D430077F3A8 /* FJ_SafeUITests.m */; }; 18 | 640EA1E921800B1400060D3D /* NSMutableAttributedString+Safe.m in Sources */ = {isa = PBXBuildFile; fileRef = 640EA1D721800B1300060D3D /* NSMutableAttributedString+Safe.m */; }; 19 | 640EA1EA21800B1400060D3D /* NSArray+Safe.m in Sources */ = {isa = PBXBuildFile; fileRef = 640EA1DB21800B1300060D3D /* NSArray+Safe.m */; }; 20 | 640EA1EB21800B1400060D3D /* NSMutableDictionary+Safe.m in Sources */ = {isa = PBXBuildFile; fileRef = 640EA1DC21800B1300060D3D /* NSMutableDictionary+Safe.m */; }; 21 | 640EA1EC21800B1400060D3D /* NSDictionary+Safe.m in Sources */ = {isa = PBXBuildFile; fileRef = 640EA1DF21800B1300060D3D /* NSDictionary+Safe.m */; }; 22 | 640EA1ED21800B1400060D3D /* NSMutableArray+Safe.m in Sources */ = {isa = PBXBuildFile; fileRef = 640EA1E021800B1300060D3D /* NSMutableArray+Safe.m */; }; 23 | 640EA1EE21800B1400060D3D /* NSAttributedString+Safe.m in Sources */ = {isa = PBXBuildFile; fileRef = 640EA1E121800B1300060D3D /* NSAttributedString+Safe.m */; }; 24 | 640EA1EF21800B1400060D3D /* NSMutableString+Safe.m in Sources */ = {isa = PBXBuildFile; fileRef = 640EA1E421800B1300060D3D /* NSMutableString+Safe.m */; }; 25 | 640EA1F021800B1400060D3D /* NSObject+Swizzling.m in Sources */ = {isa = PBXBuildFile; fileRef = 640EA1E521800B1300060D3D /* NSObject+Swizzling.m */; }; 26 | 640EA1F121800B1400060D3D /* NSString+Safe.m in Sources */ = {isa = PBXBuildFile; fileRef = 640EA1E821800B1400060D3D /* NSString+Safe.m */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXContainerItemProxy section */ 30 | 30426B541E1E7D430077F3A8 /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = 30426B321E1E7D430077F3A8 /* Project object */; 33 | proxyType = 1; 34 | remoteGlobalIDString = 30426B391E1E7D430077F3A8; 35 | remoteInfo = FJ_Safe; 36 | }; 37 | 30426B5F1E1E7D430077F3A8 /* PBXContainerItemProxy */ = { 38 | isa = PBXContainerItemProxy; 39 | containerPortal = 30426B321E1E7D430077F3A8 /* Project object */; 40 | proxyType = 1; 41 | remoteGlobalIDString = 30426B391E1E7D430077F3A8; 42 | remoteInfo = FJ_Safe; 43 | }; 44 | /* End PBXContainerItemProxy section */ 45 | 46 | /* Begin PBXFileReference section */ 47 | 30426B3A1E1E7D430077F3A8 /* FJ_Safe.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FJ_Safe.app; sourceTree = BUILT_PRODUCTS_DIR; }; 48 | 30426B3E1E1E7D430077F3A8 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 49 | 30426B401E1E7D430077F3A8 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 50 | 30426B411E1E7D430077F3A8 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 51 | 30426B431E1E7D430077F3A8 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 52 | 30426B441E1E7D430077F3A8 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 53 | 30426B471E1E7D430077F3A8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 54 | 30426B491E1E7D430077F3A8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 55 | 30426B4C1E1E7D430077F3A8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 56 | 30426B4E1E1E7D430077F3A8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 57 | 30426B531E1E7D430077F3A8 /* FJ_SafeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FJ_SafeTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | 30426B571E1E7D430077F3A8 /* FJ_SafeTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FJ_SafeTests.m; sourceTree = ""; }; 59 | 30426B591E1E7D430077F3A8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 60 | 30426B5E1E1E7D430077F3A8 /* FJ_SafeUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FJ_SafeUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 61 | 30426B621E1E7D430077F3A8 /* FJ_SafeUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FJ_SafeUITests.m; sourceTree = ""; }; 62 | 30426B641E1E7D430077F3A8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 63 | 640EA1D721800B1300060D3D /* NSMutableAttributedString+Safe.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableAttributedString+Safe.m"; sourceTree = ""; }; 64 | 640EA1D821800B1300060D3D /* NSMutableString+Safe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableString+Safe.h"; sourceTree = ""; }; 65 | 640EA1D921800B1300060D3D /* NSDictionary+Safe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Safe.h"; sourceTree = ""; }; 66 | 640EA1DA21800B1300060D3D /* NSArray+Safe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Safe.h"; sourceTree = ""; }; 67 | 640EA1DB21800B1300060D3D /* NSArray+Safe.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Safe.m"; sourceTree = ""; }; 68 | 640EA1DC21800B1300060D3D /* NSMutableDictionary+Safe.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableDictionary+Safe.m"; sourceTree = ""; }; 69 | 640EA1DD21800B1300060D3D /* NSString+Safe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+Safe.h"; sourceTree = ""; }; 70 | 640EA1DE21800B1300060D3D /* NSMutableDictionary+Safe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableDictionary+Safe.h"; sourceTree = ""; }; 71 | 640EA1DF21800B1300060D3D /* NSDictionary+Safe.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+Safe.m"; sourceTree = ""; }; 72 | 640EA1E021800B1300060D3D /* NSMutableArray+Safe.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableArray+Safe.m"; sourceTree = ""; }; 73 | 640EA1E121800B1300060D3D /* NSAttributedString+Safe.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSAttributedString+Safe.m"; sourceTree = ""; }; 74 | 640EA1E221800B1300060D3D /* NSObject+Swizzling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+Swizzling.h"; sourceTree = ""; }; 75 | 640EA1E321800B1300060D3D /* NSAttributedString+Safe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSAttributedString+Safe.h"; sourceTree = ""; }; 76 | 640EA1E421800B1300060D3D /* NSMutableString+Safe.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableString+Safe.m"; sourceTree = ""; }; 77 | 640EA1E521800B1300060D3D /* NSObject+Swizzling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+Swizzling.m"; sourceTree = ""; }; 78 | 640EA1E621800B1300060D3D /* NSMutableArray+Safe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableArray+Safe.h"; sourceTree = ""; }; 79 | 640EA1E721800B1400060D3D /* NSMutableAttributedString+Safe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableAttributedString+Safe.h"; sourceTree = ""; }; 80 | 640EA1E821800B1400060D3D /* NSString+Safe.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+Safe.m"; sourceTree = ""; }; 81 | /* End PBXFileReference section */ 82 | 83 | /* Begin PBXFrameworksBuildPhase section */ 84 | 30426B371E1E7D430077F3A8 /* Frameworks */ = { 85 | isa = PBXFrameworksBuildPhase; 86 | buildActionMask = 2147483647; 87 | files = ( 88 | ); 89 | runOnlyForDeploymentPostprocessing = 0; 90 | }; 91 | 30426B501E1E7D430077F3A8 /* Frameworks */ = { 92 | isa = PBXFrameworksBuildPhase; 93 | buildActionMask = 2147483647; 94 | files = ( 95 | ); 96 | runOnlyForDeploymentPostprocessing = 0; 97 | }; 98 | 30426B5B1E1E7D430077F3A8 /* Frameworks */ = { 99 | isa = PBXFrameworksBuildPhase; 100 | buildActionMask = 2147483647; 101 | files = ( 102 | ); 103 | runOnlyForDeploymentPostprocessing = 0; 104 | }; 105 | /* End PBXFrameworksBuildPhase section */ 106 | 107 | /* Begin PBXGroup section */ 108 | 30426B311E1E7D430077F3A8 = { 109 | isa = PBXGroup; 110 | children = ( 111 | 309497D81F6FAFF000C565ED /* FJAvoidCrashMechanism */, 112 | 30426B3C1E1E7D430077F3A8 /* FJ_Safe */, 113 | 30426B561E1E7D430077F3A8 /* FJ_SafeTests */, 114 | 30426B611E1E7D430077F3A8 /* FJ_SafeUITests */, 115 | 30426B3B1E1E7D430077F3A8 /* Products */, 116 | ); 117 | sourceTree = ""; 118 | }; 119 | 30426B3B1E1E7D430077F3A8 /* Products */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | 30426B3A1E1E7D430077F3A8 /* FJ_Safe.app */, 123 | 30426B531E1E7D430077F3A8 /* FJ_SafeTests.xctest */, 124 | 30426B5E1E1E7D430077F3A8 /* FJ_SafeUITests.xctest */, 125 | ); 126 | name = Products; 127 | sourceTree = ""; 128 | }; 129 | 30426B3C1E1E7D430077F3A8 /* FJ_Safe */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | 30426B401E1E7D430077F3A8 /* AppDelegate.h */, 133 | 30426B411E1E7D430077F3A8 /* AppDelegate.m */, 134 | 30426B431E1E7D430077F3A8 /* ViewController.h */, 135 | 30426B441E1E7D430077F3A8 /* ViewController.m */, 136 | 30426B461E1E7D430077F3A8 /* Main.storyboard */, 137 | 30426B491E1E7D430077F3A8 /* Assets.xcassets */, 138 | 30426B4B1E1E7D430077F3A8 /* LaunchScreen.storyboard */, 139 | 30426B4E1E1E7D430077F3A8 /* Info.plist */, 140 | 30426B3D1E1E7D430077F3A8 /* Supporting Files */, 141 | ); 142 | path = FJ_Safe; 143 | sourceTree = ""; 144 | }; 145 | 30426B3D1E1E7D430077F3A8 /* Supporting Files */ = { 146 | isa = PBXGroup; 147 | children = ( 148 | 30426B3E1E1E7D430077F3A8 /* main.m */, 149 | ); 150 | name = "Supporting Files"; 151 | sourceTree = ""; 152 | }; 153 | 30426B561E1E7D430077F3A8 /* FJ_SafeTests */ = { 154 | isa = PBXGroup; 155 | children = ( 156 | 30426B571E1E7D430077F3A8 /* FJ_SafeTests.m */, 157 | 30426B591E1E7D430077F3A8 /* Info.plist */, 158 | ); 159 | path = FJ_SafeTests; 160 | sourceTree = ""; 161 | }; 162 | 30426B611E1E7D430077F3A8 /* FJ_SafeUITests */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | 30426B621E1E7D430077F3A8 /* FJ_SafeUITests.m */, 166 | 30426B641E1E7D430077F3A8 /* Info.plist */, 167 | ); 168 | path = FJ_SafeUITests; 169 | sourceTree = ""; 170 | }; 171 | 309497D81F6FAFF000C565ED /* FJAvoidCrashMechanism */ = { 172 | isa = PBXGroup; 173 | children = ( 174 | 640EA1DA21800B1300060D3D /* NSArray+Safe.h */, 175 | 640EA1DB21800B1300060D3D /* NSArray+Safe.m */, 176 | 640EA1E321800B1300060D3D /* NSAttributedString+Safe.h */, 177 | 640EA1E121800B1300060D3D /* NSAttributedString+Safe.m */, 178 | 640EA1D921800B1300060D3D /* NSDictionary+Safe.h */, 179 | 640EA1DF21800B1300060D3D /* NSDictionary+Safe.m */, 180 | 640EA1E621800B1300060D3D /* NSMutableArray+Safe.h */, 181 | 640EA1E021800B1300060D3D /* NSMutableArray+Safe.m */, 182 | 640EA1E721800B1400060D3D /* NSMutableAttributedString+Safe.h */, 183 | 640EA1D721800B1300060D3D /* NSMutableAttributedString+Safe.m */, 184 | 640EA1DE21800B1300060D3D /* NSMutableDictionary+Safe.h */, 185 | 640EA1DC21800B1300060D3D /* NSMutableDictionary+Safe.m */, 186 | 640EA1D821800B1300060D3D /* NSMutableString+Safe.h */, 187 | 640EA1E421800B1300060D3D /* NSMutableString+Safe.m */, 188 | 640EA1E221800B1300060D3D /* NSObject+Swizzling.h */, 189 | 640EA1E521800B1300060D3D /* NSObject+Swizzling.m */, 190 | 640EA1DD21800B1300060D3D /* NSString+Safe.h */, 191 | 640EA1E821800B1400060D3D /* NSString+Safe.m */, 192 | ); 193 | path = FJAvoidCrashMechanism; 194 | sourceTree = ""; 195 | }; 196 | /* End PBXGroup section */ 197 | 198 | /* Begin PBXNativeTarget section */ 199 | 30426B391E1E7D430077F3A8 /* FJ_Safe */ = { 200 | isa = PBXNativeTarget; 201 | buildConfigurationList = 30426B671E1E7D430077F3A8 /* Build configuration list for PBXNativeTarget "FJ_Safe" */; 202 | buildPhases = ( 203 | 30426B361E1E7D430077F3A8 /* Sources */, 204 | 30426B371E1E7D430077F3A8 /* Frameworks */, 205 | 30426B381E1E7D430077F3A8 /* Resources */, 206 | ); 207 | buildRules = ( 208 | ); 209 | dependencies = ( 210 | ); 211 | name = FJ_Safe; 212 | productName = FJ_Safe; 213 | productReference = 30426B3A1E1E7D430077F3A8 /* FJ_Safe.app */; 214 | productType = "com.apple.product-type.application"; 215 | }; 216 | 30426B521E1E7D430077F3A8 /* FJ_SafeTests */ = { 217 | isa = PBXNativeTarget; 218 | buildConfigurationList = 30426B6A1E1E7D430077F3A8 /* Build configuration list for PBXNativeTarget "FJ_SafeTests" */; 219 | buildPhases = ( 220 | 30426B4F1E1E7D430077F3A8 /* Sources */, 221 | 30426B501E1E7D430077F3A8 /* Frameworks */, 222 | 30426B511E1E7D430077F3A8 /* Resources */, 223 | ); 224 | buildRules = ( 225 | ); 226 | dependencies = ( 227 | 30426B551E1E7D430077F3A8 /* PBXTargetDependency */, 228 | ); 229 | name = FJ_SafeTests; 230 | productName = FJ_SafeTests; 231 | productReference = 30426B531E1E7D430077F3A8 /* FJ_SafeTests.xctest */; 232 | productType = "com.apple.product-type.bundle.unit-test"; 233 | }; 234 | 30426B5D1E1E7D430077F3A8 /* FJ_SafeUITests */ = { 235 | isa = PBXNativeTarget; 236 | buildConfigurationList = 30426B6D1E1E7D430077F3A8 /* Build configuration list for PBXNativeTarget "FJ_SafeUITests" */; 237 | buildPhases = ( 238 | 30426B5A1E1E7D430077F3A8 /* Sources */, 239 | 30426B5B1E1E7D430077F3A8 /* Frameworks */, 240 | 30426B5C1E1E7D430077F3A8 /* Resources */, 241 | ); 242 | buildRules = ( 243 | ); 244 | dependencies = ( 245 | 30426B601E1E7D430077F3A8 /* PBXTargetDependency */, 246 | ); 247 | name = FJ_SafeUITests; 248 | productName = FJ_SafeUITests; 249 | productReference = 30426B5E1E1E7D430077F3A8 /* FJ_SafeUITests.xctest */; 250 | productType = "com.apple.product-type.bundle.ui-testing"; 251 | }; 252 | /* End PBXNativeTarget section */ 253 | 254 | /* Begin PBXProject section */ 255 | 30426B321E1E7D430077F3A8 /* Project object */ = { 256 | isa = PBXProject; 257 | attributes = { 258 | LastUpgradeCheck = 0810; 259 | ORGANIZATIONNAME = fjf; 260 | TargetAttributes = { 261 | 30426B391E1E7D430077F3A8 = { 262 | CreatedOnToolsVersion = 8.1; 263 | DevelopmentTeam = L8R666257B; 264 | ProvisioningStyle = Automatic; 265 | }; 266 | 30426B521E1E7D430077F3A8 = { 267 | CreatedOnToolsVersion = 8.1; 268 | ProvisioningStyle = Automatic; 269 | TestTargetID = 30426B391E1E7D430077F3A8; 270 | }; 271 | 30426B5D1E1E7D430077F3A8 = { 272 | CreatedOnToolsVersion = 8.1; 273 | ProvisioningStyle = Automatic; 274 | TestTargetID = 30426B391E1E7D430077F3A8; 275 | }; 276 | }; 277 | }; 278 | buildConfigurationList = 30426B351E1E7D430077F3A8 /* Build configuration list for PBXProject "FJ_Safe" */; 279 | compatibilityVersion = "Xcode 3.2"; 280 | developmentRegion = English; 281 | hasScannedForEncodings = 0; 282 | knownRegions = ( 283 | en, 284 | Base, 285 | ); 286 | mainGroup = 30426B311E1E7D430077F3A8; 287 | productRefGroup = 30426B3B1E1E7D430077F3A8 /* Products */; 288 | projectDirPath = ""; 289 | projectRoot = ""; 290 | targets = ( 291 | 30426B391E1E7D430077F3A8 /* FJ_Safe */, 292 | 30426B521E1E7D430077F3A8 /* FJ_SafeTests */, 293 | 30426B5D1E1E7D430077F3A8 /* FJ_SafeUITests */, 294 | ); 295 | }; 296 | /* End PBXProject section */ 297 | 298 | /* Begin PBXResourcesBuildPhase section */ 299 | 30426B381E1E7D430077F3A8 /* Resources */ = { 300 | isa = PBXResourcesBuildPhase; 301 | buildActionMask = 2147483647; 302 | files = ( 303 | 30426B4D1E1E7D430077F3A8 /* LaunchScreen.storyboard in Resources */, 304 | 30426B4A1E1E7D430077F3A8 /* Assets.xcassets in Resources */, 305 | 30426B481E1E7D430077F3A8 /* Main.storyboard in Resources */, 306 | ); 307 | runOnlyForDeploymentPostprocessing = 0; 308 | }; 309 | 30426B511E1E7D430077F3A8 /* Resources */ = { 310 | isa = PBXResourcesBuildPhase; 311 | buildActionMask = 2147483647; 312 | files = ( 313 | ); 314 | runOnlyForDeploymentPostprocessing = 0; 315 | }; 316 | 30426B5C1E1E7D430077F3A8 /* Resources */ = { 317 | isa = PBXResourcesBuildPhase; 318 | buildActionMask = 2147483647; 319 | files = ( 320 | ); 321 | runOnlyForDeploymentPostprocessing = 0; 322 | }; 323 | /* End PBXResourcesBuildPhase section */ 324 | 325 | /* Begin PBXSourcesBuildPhase section */ 326 | 30426B361E1E7D430077F3A8 /* Sources */ = { 327 | isa = PBXSourcesBuildPhase; 328 | buildActionMask = 2147483647; 329 | files = ( 330 | 640EA1EB21800B1400060D3D /* NSMutableDictionary+Safe.m in Sources */, 331 | 640EA1EF21800B1400060D3D /* NSMutableString+Safe.m in Sources */, 332 | 30426B451E1E7D430077F3A8 /* ViewController.m in Sources */, 333 | 640EA1EA21800B1400060D3D /* NSArray+Safe.m in Sources */, 334 | 640EA1F121800B1400060D3D /* NSString+Safe.m in Sources */, 335 | 30426B421E1E7D430077F3A8 /* AppDelegate.m in Sources */, 336 | 640EA1F021800B1400060D3D /* NSObject+Swizzling.m in Sources */, 337 | 640EA1ED21800B1400060D3D /* NSMutableArray+Safe.m in Sources */, 338 | 640EA1EC21800B1400060D3D /* NSDictionary+Safe.m in Sources */, 339 | 640EA1EE21800B1400060D3D /* NSAttributedString+Safe.m in Sources */, 340 | 640EA1E921800B1400060D3D /* NSMutableAttributedString+Safe.m in Sources */, 341 | 30426B3F1E1E7D430077F3A8 /* main.m in Sources */, 342 | ); 343 | runOnlyForDeploymentPostprocessing = 0; 344 | }; 345 | 30426B4F1E1E7D430077F3A8 /* Sources */ = { 346 | isa = PBXSourcesBuildPhase; 347 | buildActionMask = 2147483647; 348 | files = ( 349 | 30426B581E1E7D430077F3A8 /* FJ_SafeTests.m in Sources */, 350 | ); 351 | runOnlyForDeploymentPostprocessing = 0; 352 | }; 353 | 30426B5A1E1E7D430077F3A8 /* Sources */ = { 354 | isa = PBXSourcesBuildPhase; 355 | buildActionMask = 2147483647; 356 | files = ( 357 | 30426B631E1E7D430077F3A8 /* FJ_SafeUITests.m in Sources */, 358 | ); 359 | runOnlyForDeploymentPostprocessing = 0; 360 | }; 361 | /* End PBXSourcesBuildPhase section */ 362 | 363 | /* Begin PBXTargetDependency section */ 364 | 30426B551E1E7D430077F3A8 /* PBXTargetDependency */ = { 365 | isa = PBXTargetDependency; 366 | target = 30426B391E1E7D430077F3A8 /* FJ_Safe */; 367 | targetProxy = 30426B541E1E7D430077F3A8 /* PBXContainerItemProxy */; 368 | }; 369 | 30426B601E1E7D430077F3A8 /* PBXTargetDependency */ = { 370 | isa = PBXTargetDependency; 371 | target = 30426B391E1E7D430077F3A8 /* FJ_Safe */; 372 | targetProxy = 30426B5F1E1E7D430077F3A8 /* PBXContainerItemProxy */; 373 | }; 374 | /* End PBXTargetDependency section */ 375 | 376 | /* Begin PBXVariantGroup section */ 377 | 30426B461E1E7D430077F3A8 /* Main.storyboard */ = { 378 | isa = PBXVariantGroup; 379 | children = ( 380 | 30426B471E1E7D430077F3A8 /* Base */, 381 | ); 382 | name = Main.storyboard; 383 | sourceTree = ""; 384 | }; 385 | 30426B4B1E1E7D430077F3A8 /* LaunchScreen.storyboard */ = { 386 | isa = PBXVariantGroup; 387 | children = ( 388 | 30426B4C1E1E7D430077F3A8 /* Base */, 389 | ); 390 | name = LaunchScreen.storyboard; 391 | sourceTree = ""; 392 | }; 393 | /* End PBXVariantGroup section */ 394 | 395 | /* Begin XCBuildConfiguration section */ 396 | 30426B651E1E7D430077F3A8 /* Debug */ = { 397 | isa = XCBuildConfiguration; 398 | buildSettings = { 399 | ALWAYS_SEARCH_USER_PATHS = NO; 400 | CLANG_ANALYZER_NONNULL = YES; 401 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 402 | CLANG_CXX_LIBRARY = "libc++"; 403 | CLANG_ENABLE_MODULES = YES; 404 | CLANG_ENABLE_OBJC_ARC = YES; 405 | CLANG_WARN_BOOL_CONVERSION = YES; 406 | CLANG_WARN_CONSTANT_CONVERSION = YES; 407 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 408 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 409 | CLANG_WARN_EMPTY_BODY = YES; 410 | CLANG_WARN_ENUM_CONVERSION = YES; 411 | CLANG_WARN_INFINITE_RECURSION = YES; 412 | CLANG_WARN_INT_CONVERSION = YES; 413 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 414 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 415 | CLANG_WARN_UNREACHABLE_CODE = YES; 416 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 417 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 418 | COPY_PHASE_STRIP = NO; 419 | DEBUG_INFORMATION_FORMAT = dwarf; 420 | ENABLE_STRICT_OBJC_MSGSEND = YES; 421 | ENABLE_TESTABILITY = YES; 422 | GCC_C_LANGUAGE_STANDARD = gnu99; 423 | GCC_DYNAMIC_NO_PIC = NO; 424 | GCC_NO_COMMON_BLOCKS = YES; 425 | GCC_OPTIMIZATION_LEVEL = 0; 426 | GCC_PREPROCESSOR_DEFINITIONS = ( 427 | "DEBUG=1", 428 | "$(inherited)", 429 | ); 430 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 431 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 432 | GCC_WARN_UNDECLARED_SELECTOR = YES; 433 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 434 | GCC_WARN_UNUSED_FUNCTION = YES; 435 | GCC_WARN_UNUSED_VARIABLE = YES; 436 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 437 | MTL_ENABLE_DEBUG_INFO = YES; 438 | ONLY_ACTIVE_ARCH = YES; 439 | SDKROOT = iphoneos; 440 | TARGETED_DEVICE_FAMILY = "1,2"; 441 | }; 442 | name = Debug; 443 | }; 444 | 30426B661E1E7D430077F3A8 /* Release */ = { 445 | isa = XCBuildConfiguration; 446 | buildSettings = { 447 | ALWAYS_SEARCH_USER_PATHS = NO; 448 | CLANG_ANALYZER_NONNULL = YES; 449 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 450 | CLANG_CXX_LIBRARY = "libc++"; 451 | CLANG_ENABLE_MODULES = YES; 452 | CLANG_ENABLE_OBJC_ARC = YES; 453 | CLANG_WARN_BOOL_CONVERSION = YES; 454 | CLANG_WARN_CONSTANT_CONVERSION = YES; 455 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 456 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 457 | CLANG_WARN_EMPTY_BODY = YES; 458 | CLANG_WARN_ENUM_CONVERSION = YES; 459 | CLANG_WARN_INFINITE_RECURSION = YES; 460 | CLANG_WARN_INT_CONVERSION = YES; 461 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 462 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 463 | CLANG_WARN_UNREACHABLE_CODE = YES; 464 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 465 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 466 | COPY_PHASE_STRIP = NO; 467 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 468 | ENABLE_NS_ASSERTIONS = NO; 469 | ENABLE_STRICT_OBJC_MSGSEND = YES; 470 | GCC_C_LANGUAGE_STANDARD = gnu99; 471 | GCC_NO_COMMON_BLOCKS = YES; 472 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 473 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 474 | GCC_WARN_UNDECLARED_SELECTOR = YES; 475 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 476 | GCC_WARN_UNUSED_FUNCTION = YES; 477 | GCC_WARN_UNUSED_VARIABLE = YES; 478 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 479 | MTL_ENABLE_DEBUG_INFO = NO; 480 | SDKROOT = iphoneos; 481 | TARGETED_DEVICE_FAMILY = "1,2"; 482 | VALIDATE_PRODUCT = YES; 483 | }; 484 | name = Release; 485 | }; 486 | 30426B681E1E7D430077F3A8 /* Debug */ = { 487 | isa = XCBuildConfiguration; 488 | buildSettings = { 489 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 490 | DEVELOPMENT_TEAM = L8R666257B; 491 | INFOPLIST_FILE = FJ_Safe/Info.plist; 492 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 493 | PRODUCT_BUNDLE_IDENTIFIER = "test.FJ-Safe"; 494 | PRODUCT_NAME = "$(TARGET_NAME)"; 495 | }; 496 | name = Debug; 497 | }; 498 | 30426B691E1E7D430077F3A8 /* Release */ = { 499 | isa = XCBuildConfiguration; 500 | buildSettings = { 501 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 502 | DEVELOPMENT_TEAM = L8R666257B; 503 | INFOPLIST_FILE = FJ_Safe/Info.plist; 504 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 505 | PRODUCT_BUNDLE_IDENTIFIER = "test.FJ-Safe"; 506 | PRODUCT_NAME = "$(TARGET_NAME)"; 507 | }; 508 | name = Release; 509 | }; 510 | 30426B6B1E1E7D430077F3A8 /* Debug */ = { 511 | isa = XCBuildConfiguration; 512 | buildSettings = { 513 | BUNDLE_LOADER = "$(TEST_HOST)"; 514 | INFOPLIST_FILE = FJ_SafeTests/Info.plist; 515 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 516 | PRODUCT_BUNDLE_IDENTIFIER = "test.FJ-SafeTests"; 517 | PRODUCT_NAME = "$(TARGET_NAME)"; 518 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FJ_Safe.app/FJ_Safe"; 519 | }; 520 | name = Debug; 521 | }; 522 | 30426B6C1E1E7D430077F3A8 /* Release */ = { 523 | isa = XCBuildConfiguration; 524 | buildSettings = { 525 | BUNDLE_LOADER = "$(TEST_HOST)"; 526 | INFOPLIST_FILE = FJ_SafeTests/Info.plist; 527 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 528 | PRODUCT_BUNDLE_IDENTIFIER = "test.FJ-SafeTests"; 529 | PRODUCT_NAME = "$(TARGET_NAME)"; 530 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FJ_Safe.app/FJ_Safe"; 531 | }; 532 | name = Release; 533 | }; 534 | 30426B6E1E1E7D430077F3A8 /* Debug */ = { 535 | isa = XCBuildConfiguration; 536 | buildSettings = { 537 | INFOPLIST_FILE = FJ_SafeUITests/Info.plist; 538 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 539 | PRODUCT_BUNDLE_IDENTIFIER = "test.FJ-SafeUITests"; 540 | PRODUCT_NAME = "$(TARGET_NAME)"; 541 | TEST_TARGET_NAME = FJ_Safe; 542 | }; 543 | name = Debug; 544 | }; 545 | 30426B6F1E1E7D430077F3A8 /* Release */ = { 546 | isa = XCBuildConfiguration; 547 | buildSettings = { 548 | INFOPLIST_FILE = FJ_SafeUITests/Info.plist; 549 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 550 | PRODUCT_BUNDLE_IDENTIFIER = "test.FJ-SafeUITests"; 551 | PRODUCT_NAME = "$(TARGET_NAME)"; 552 | TEST_TARGET_NAME = FJ_Safe; 553 | }; 554 | name = Release; 555 | }; 556 | /* End XCBuildConfiguration section */ 557 | 558 | /* Begin XCConfigurationList section */ 559 | 30426B351E1E7D430077F3A8 /* Build configuration list for PBXProject "FJ_Safe" */ = { 560 | isa = XCConfigurationList; 561 | buildConfigurations = ( 562 | 30426B651E1E7D430077F3A8 /* Debug */, 563 | 30426B661E1E7D430077F3A8 /* Release */, 564 | ); 565 | defaultConfigurationIsVisible = 0; 566 | defaultConfigurationName = Release; 567 | }; 568 | 30426B671E1E7D430077F3A8 /* Build configuration list for PBXNativeTarget "FJ_Safe" */ = { 569 | isa = XCConfigurationList; 570 | buildConfigurations = ( 571 | 30426B681E1E7D430077F3A8 /* Debug */, 572 | 30426B691E1E7D430077F3A8 /* Release */, 573 | ); 574 | defaultConfigurationIsVisible = 0; 575 | defaultConfigurationName = Release; 576 | }; 577 | 30426B6A1E1E7D430077F3A8 /* Build configuration list for PBXNativeTarget "FJ_SafeTests" */ = { 578 | isa = XCConfigurationList; 579 | buildConfigurations = ( 580 | 30426B6B1E1E7D430077F3A8 /* Debug */, 581 | 30426B6C1E1E7D430077F3A8 /* Release */, 582 | ); 583 | defaultConfigurationIsVisible = 0; 584 | defaultConfigurationName = Release; 585 | }; 586 | 30426B6D1E1E7D430077F3A8 /* Build configuration list for PBXNativeTarget "FJ_SafeUITests" */ = { 587 | isa = XCConfigurationList; 588 | buildConfigurations = ( 589 | 30426B6E1E1E7D430077F3A8 /* Debug */, 590 | 30426B6F1E1E7D430077F3A8 /* Release */, 591 | ); 592 | defaultConfigurationIsVisible = 0; 593 | defaultConfigurationName = Release; 594 | }; 595 | /* End XCConfigurationList section */ 596 | }; 597 | rootObject = 30426B321E1E7D430077F3A8 /* Project object */; 598 | } 599 | -------------------------------------------------------------------------------- /FJ_Safe.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /FJ_Safe.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /FJ_Safe.xcodeproj/project.xcworkspace/xcuserdata/fangjinfeng.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fangjinfeng/FJ_Safe/9db29ac1d4e79e9f5a19351725e2e78c27bae607/FJ_Safe.xcodeproj/project.xcworkspace/xcuserdata/fangjinfeng.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /FJ_Safe.xcodeproj/project.xcworkspace/xcuserdata/fjf.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fangjinfeng/FJ_Safe/9db29ac1d4e79e9f5a19351725e2e78c27bae607/FJ_Safe.xcodeproj/project.xcworkspace/xcuserdata/fjf.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /FJ_Safe.xcodeproj/xcuserdata/fangjinfeng.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | FJ_Safe.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /FJ_Safe.xcodeproj/xcuserdata/fjf.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 24 | 36 | 37 | 38 | 40 | 52 | 53 | 54 | 56 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /FJ_Safe.xcodeproj/xcuserdata/fjf.xcuserdatad/xcschemes/FJ_Safe.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /FJ_Safe.xcodeproj/xcuserdata/fjf.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | FJ_Safe.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 30426B391E1E7D430077F3A8 16 | 17 | primary 18 | 19 | 20 | 30426B521E1E7D430077F3A8 21 | 22 | primary 23 | 24 | 25 | 30426B5D1E1E7D430077F3A8 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /FJ_Safe/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // FJ_Safe 4 | // 5 | // Created by fjf on 2017/1/5. 6 | // Copyright © 2017年 fjf. 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 | -------------------------------------------------------------------------------- /FJ_Safe/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // FJ_Safe 4 | // 5 | // Created by fjf on 2017/1/5. 6 | // Copyright © 2017年 fjf. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "ViewController.h" 11 | 12 | @interface AppDelegate () 13 | 14 | @end 15 | 16 | @implementation AppDelegate 17 | 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 20 | // Override point for customization after application launch. 21 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 22 | 23 | self.window.rootViewController = [[ViewController alloc] init]; 24 | 25 | [self.window makeKeyAndVisible]; 26 | return YES; 27 | } 28 | 29 | 30 | - (void)applicationWillResignActive:(UIApplication *)application { 31 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 32 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 33 | } 34 | 35 | 36 | - (void)applicationDidEnterBackground:(UIApplication *)application { 37 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 38 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 39 | } 40 | 41 | 42 | - (void)applicationWillEnterForeground:(UIApplication *)application { 43 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 44 | } 45 | 46 | 47 | - (void)applicationDidBecomeActive:(UIApplication *)application { 48 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 49 | } 50 | 51 | 52 | - (void)applicationWillTerminate:(UIApplication *)application { 53 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 54 | } 55 | 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /FJ_Safe/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 | } -------------------------------------------------------------------------------- /FJ_Safe/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 | -------------------------------------------------------------------------------- /FJ_Safe/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 | -------------------------------------------------------------------------------- /FJ_Safe/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.4 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /FJ_Safe/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // FJ_Safe 4 | // 5 | // Created by fjf on 2017/1/5. 6 | // Copyright © 2017年 fjf. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /FJ_Safe/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // FJ_Safe 4 | // 5 | // Created by fjf on 2017/1/5. 6 | // Copyright © 2017年 fjf. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | @interface ViewController () 12 | 13 | @end 14 | 15 | @implementation ViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | // __NSCFConstantString 类型 21 | NSString *tmpConstantString = @"432423432432432432"; 22 | [tmpConstantString substringFromIndex:10000]; 23 | [tmpConstantString substringToIndex:1000]; 24 | [tmpConstantString substringWithRange:NSMakeRange(100, 10000)]; 25 | [tmpConstantString rangeOfString:nil]; 26 | 27 | // NSTaggedPointerString 类型 28 | NSString *tmpPointerString = [NSString stringWithFormat:@"4"]; 29 | [tmpPointerString substringFromIndex:10000]; 30 | [tmpPointerString substringToIndex:1000]; 31 | [tmpPointerString substringWithRange:NSMakeRange(100, 10000)]; 32 | [tmpPointerString rangeOfString:nil]; 33 | 34 | // __NSCFString 类型(备注:类似这样:[NSString stringWithFormat:@"4535435435435"]出来也是__NSCFString,因为NSMutableString初始化出来都是__NSCFString类型,所以归到NSMutableString里面) 35 | NSMutableString *tmpCFString = [NSMutableString stringWithFormat:@"4535435435435"]; 36 | [tmpCFString substringFromIndex:10000]; 37 | [tmpCFString substringToIndex:1000]; 38 | [tmpCFString substringWithRange:NSMakeRange(100, 10000)]; 39 | [tmpCFString rangeOfString:nil]; 40 | [tmpCFString appendString:nil]; 41 | 42 | // __NSArray0 类型 43 | NSArray *tmpZoroArray = [NSArray array]; 44 | tmpZoroArray[100]; 45 | [tmpZoroArray objectAtIndex:1000]; 46 | 47 | // __NSSingleObjectArrayI 类型 48 | NSArray *tmpSingleObjectArray = [NSArray arrayWithObject:@"200"]; 49 | tmpSingleObjectArray[100]; 50 | [tmpSingleObjectArray objectAtIndex:1000]; 51 | 52 | // __NSArrayI 类型 53 | NSArray *tmpArrayI = [NSArray arrayWithObjects:@"1",@"2", nil]; 54 | tmpArrayI[100]; 55 | [tmpArrayI objectAtIndex:1000]; 56 | 57 | // __NSArrayM 类型 58 | NSMutableArray *tmpMutableArrayM = [NSMutableArray arrayWithCapacity:0]; 59 | tmpMutableArrayM[100]; 60 | [tmpMutableArrayM objectAtIndex:1000]; 61 | [tmpMutableArrayM insertObject:nil atIndex:10000]; 62 | [tmpMutableArrayM removeObject:nil]; 63 | [tmpMutableArrayM removeObjectAtIndex:1000]; 64 | [tmpMutableArrayM removeObjectsInRange:NSMakeRange(-100, 10000)]; 65 | 66 | [tmpMutableArrayM addObject:nil]; 67 | 68 | 69 | // __NSDictionaryM 类型 70 | NSMutableDictionary *tmpMutableDictM = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"100",@"A",@"200",@"B", nil]; 71 | [tmpMutableDictM removeObjectForKey:nil]; 72 | [tmpMutableDictM setObject:nil forKey:@"C"]; 73 | [tmpMutableDictM setObject:@"300" forKey:nil]; 74 | 75 | } 76 | 77 | 78 | - (void)didReceiveMemoryWarning { 79 | [super didReceiveMemoryWarning]; 80 | // Dispose of any resources that can be recreated. 81 | } 82 | 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /FJ_Safe/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // FJ_Safe 4 | // 5 | // Created by fjf on 2017/1/5. 6 | // Copyright © 2017年 fjf. 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 | -------------------------------------------------------------------------------- /FJ_SafeTests/FJ_SafeTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // FJ_SafeTests.m 3 | // FJ_SafeTests 4 | // 5 | // Created by fjf on 2017/1/5. 6 | // Copyright © 2017年 fjf. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface FJ_SafeTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation FJ_SafeTests 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 | -------------------------------------------------------------------------------- /FJ_SafeTests/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 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /FJ_SafeUITests/FJ_SafeUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // FJ_SafeUITests.m 3 | // FJ_SafeUITests 4 | // 5 | // Created by fjf on 2017/1/5. 6 | // Copyright © 2017年 fjf. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface FJ_SafeUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation FJ_SafeUITests 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 | -------------------------------------------------------------------------------- /FJ_SafeUITests/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 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fangjinfeng/FJ_Safe/9db29ac1d4e79e9f5a19351725e2e78c27bae607/LICENSE -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FJ_Safe 2 | 3 | [FJ_Safe简书链接](http://www.jianshu.com/p/bea2bfed3f3f) 4 | 5 | **支持pod操作** 6 | 7 | NSString、NSArray、NSMutableString、NSMutableArray、NSMutableDictionary通过运行时直接给原生的插入、删除、截取等操作添加判断,防止崩溃。 8 | 9 | 由于NSString、NSArray、NSMutableString、NSMutableArray、NSMutableDictionary这几个类型都是Class Clusters(类簇)设计模式设计出来的。 10 | 11 | Class Clusters(类簇)是抽象工厂模式在iOS下的一种实现,它是接口简单性和扩展性的权衡体现,在我们完全不知情的情况下,偷偷隐藏了很多具体的实现类, 12 | 只暴露出简单的接口。 13 | NSArray 的几个方法来创建实例对象: 14 | 15 | (lldb) po [NSArray array] 16 | <__NSArray0 0x600000017670>( 17 | ) 18 | (lldb) po [NSArray arrayWithObject:@"Hello,Zie"]; 19 | <__NSSingleObjectArrayI 0x600000017680>( 20 | Hello,Zie 21 | ) 22 | po [NSArray arrayWithObjects:@1,@2, nil]; 23 | <__NSArrayI 0x100500050>( 24 | 1, 25 | 2 26 | ) 27 | 28 | 通过打印可以看到由 NSArray ,创建的对象并不是 NSArray 本身,有可能是 __NSArray0 、 __NSSingleObjectArrayI 、 __NSArrayI,这里 NSArray 就是那个抽象类,而被创建出来那些奇奇怪的类就是作为具体的实现类,同时是内部私有的,所以替换系统中相应的类型对应的原生方法必须根据他实际实现类。 29 | 30 | 以NSString为例: 31 | 32 | 经研究发现NSString实际的实现类有<__NSCFConstantString、NSTaggedPointerString、__NSCFString>这三者,由于NSMutableString主要实现类是<__NSCFString>,所以将<__NSCFString>相应的替代方法放到NSMutableString相关文件里面。 33 | 34 | 35 | #import 36 | #import "NSString+Safe.h" 37 | 38 | @implementation NSString (Safe) 39 | 40 | #pragma mark --- init method 41 | 42 | + (void)load { 43 | //只执行一次这个方法 44 | static dispatch_once_t onceToken; 45 | dispatch_once(&onceToken, ^{ 46 | 47 | NSString *tmpSubFromStr = @"substringFromIndex:"; 48 | NSString *tmpSafeSubFromStr = @"safe_substringFromIndex:"; 49 | NSString *tmpSafePointSubFromStr = @"safePoint_substringFromIndex:"; 50 | 51 | 52 | [self exchangeImplementationWithClassStr:@"__NSCFConstantString" originalMethodStr:tmpSubFromStr newMethodStr:tmpSafeSubFromStr]; 53 | 54 | [self exchangeImplementationWithClassStr:@"NSTaggedPointerString" originalMethodStr:tmpSubFromStr newMethodStr:tmpSafePointSubFromStr]; 55 | 56 | 57 | 58 | NSString *tmpSubToStr = @"substringToIndex:"; 59 | NSString *tmpSafeSubToStr = @"safe_substringToIndex:"; 60 | NSString *tmpSafePointSubToStr = @"safePoint_substringToIndex:"; 61 | 62 | 63 | [self exchangeImplementationWithClassStr:@"__NSCFConstantString" originalMethodStr:tmpSubToStr newMethodStr:tmpSafeSubToStr]; 64 | 65 | [self exchangeImplementationWithClassStr:@"NSTaggedPointerString" originalMethodStr:tmpSubToStr newMethodStr:tmpSafePointSubToStr]; 66 | 67 | 68 | 69 | NSString *tmpSubRangeStr = @"substringWithRange:"; 70 | NSString *tmpSafeSubRangeStr = @"safe_substringWithRange:"; 71 | NSString *tmpSafePointSubRangeStr = @"safePoint_substringWithRange:"; 72 | 73 | 74 | [self exchangeImplementationWithClassStr:@"__NSCFConstantString" originalMethodStr:tmpSubRangeStr newMethodStr:tmpSafeSubRangeStr]; 75 | 76 | [self exchangeImplementationWithClassStr:@"NSTaggedPointerString" originalMethodStr:tmpSubRangeStr newMethodStr:tmpSafePointSubRangeStr]; 77 | 78 | 79 | 80 | NSString *tmpRangeOfStr = @"rangeOfString:options:range:locale:"; 81 | NSString *tmpSafeRangeOfStr = @"safe_rangeOfString:options:range:locale:"; 82 | NSString *tmpSafePointRangeOfStr = @"safePoint_rangeOfString:options:range:locale:"; 83 | 84 | 85 | [self exchangeImplementationWithClassStr:@"__NSCFConstantString" originalMethodStr:tmpRangeOfStr newMethodStr:tmpSafeRangeOfStr]; 86 | 87 | [self exchangeImplementationWithClassStr:@"NSTaggedPointerString" originalMethodStr:tmpRangeOfStr newMethodStr:tmpSafePointRangeOfStr]; 88 | 89 | 90 | 91 | }); 92 | 93 | } 94 | 95 | 这里因为将<__NSCFString>放到NSMutableString类别里面去替换,所以只做实例类<__NSCFConstantString、NSTaggedPointerString>的替换。 96 | 因为最终调用替换函数:method_exchangeImplementations(originalMethod, swizzledMethod);,所以: 97 | 98 | NSString *tmpSubFromStr = @"substringFromIndex:"; 99 | NSString *tmpSafeSubFromStr = @"safe_substringFromIndex:"; 100 | NSString *tmpSafePointSubFromStr = @"safePoint_substringFromIndex:"; 101 | 102 | 每一个实例类别都应该有自己相对应的替换方法,这里tmpSubFromStr是系统的方法,tmpSafeSubFromStr是<__NSCFConstantString>实例类对应的替换方法,tmpSafePointSubFromStr是NSTaggedPointerString对应的替换方法。这里虽然是NSString,可以通过: 103 | 104 | SEL originalSelector = NSSelectorFromString(originalMethodStr); 105 | SEL swizzledSelector = NSSelectorFromString(newMethodStr); 106 | 107 | 转换成相应的SEL方法。如果每个实力类没有自己对应的方法,比如说像这样: 108 | 109 | NSString *tmpSubFromStr = @"substringFromIndex:"; 110 | NSString *tmpSafeSubFromStr = @"safe_substringFromIndex:"; 111 | 112 | 113 | [self exchangeImplementationWithClassStr:@"__NSCFConstantString" originalMethodStr:tmpSubFromStr newMethodStr:tmpSafeSubFromStr]; 114 | 115 | [self exchangeImplementationWithClassStr:@"NSTaggedPointerString" originalMethodStr:tmpSubFromStr newMethodStr:tmpSafeSubFromStr]; 116 | 117 | 那最终只会对NSTaggedPointerString原来的substringFromIndex:函数进行替换,<__NSCFConstantString>实例类型的就不起作用。 118 | 119 | // 获取 method 120 | + (Method)methodOfClassStr:(NSString *)classStr selector:(SEL)selector { 121 | return class_getInstanceMethod(NSClassFromString(classStr),selector); 122 | } 123 | 124 | // 判断添加 新方法 或 新方法 替换 原来 方法 125 | + (void)exchangeImplementationWithClassStr:(NSString *)classStr originalMethodStr:(NSString *)originalMethodStr newMethodStr:(NSString *)newMethodStr { 126 | 127 | SEL originalSelector = NSSelectorFromString(originalMethodStr); 128 | SEL swizzledSelector = NSSelectorFromString(newMethodStr); 129 | 130 | Method originalMethod = [NSString methodOfClassStr:classStr selector:NSSelectorFromString(originalMethodStr)]; 131 | Method swizzledMethod = [NSString methodOfClassStr:classStr selector:NSSelectorFromString(newMethodStr)]; 132 | 133 | // 判断 是否 可以添加 新方法 134 | BOOL didAddMethod = 135 | class_addMethod(NSClassFromString(classStr), 136 | originalSelector, 137 | method_getImplementation(swizzledMethod), 138 | method_getTypeEncoding(swizzledMethod)); 139 | 140 | if (didAddMethod) { 141 | class_replaceMethod(NSClassFromString(classStr), 142 | swizzledSelector, 143 | method_getImplementation(originalMethod), 144 | method_getTypeEncoding(originalMethod)); 145 | 146 | } else { 147 | // 替换 原有 方法 148 | method_exchangeImplementations(originalMethod, swizzledMethod); 149 | } 150 | } 151 | 这段代码主要通过运行时,先判断是否可以往该实际类里面添加新方法,如果可以则添加新方法,如果不行,则替换原有的方法。但我们要替换的函数一般系统包含,所以只会走替换函数method_exchangeImplementations,但为了系统的健壮性,还是有必要先进行判断。 152 | 153 | #pragma mark --- implement method 154 | /**************************************** substringFromIndex: ***********************************/ 155 | /** 156 | 从from位置截取字符串 对应 __NSCFConstantString 157 | 158 | @param from 截取起始位置 159 | @return 截取的子字符串 160 | */ 161 | - (NSString *)safe_substringFromIndex:(NSUInteger)from { 162 | if (from > self.length ) { 163 | return nil; 164 | } 165 | return [self safe_substringFromIndex:from]; 166 | } 167 | /** 168 | 从from位置截取字符串 对应 NSTaggedPointerString 169 | 170 | @param from 截取起始位置 171 | @return 截取的子字符串 172 | */ 173 | - (NSString *)safePoint_substringFromIndex:(NSUInteger)from { 174 | if (from > self.length ) { 175 | return nil; 176 | } 177 | return [self safePoint_substringFromIndex:from]; 178 | } 179 | 180 | /**************************************** substringFromIndex: ***********************************/ 181 | /** 182 | 从开始截取到to位置的字符串 对应 __NSCFConstantString 183 | 184 | @param to 截取终点位置 185 | @return 返回截取的字符串 186 | */ 187 | - (NSString *)safe_substringToIndex:(NSUInteger)to { 188 | if (to > self.length ) { 189 | return nil; 190 | } 191 | return [self safe_substringToIndex:to]; 192 | } 193 | 194 | /** 195 | 从开始截取到to位置的字符串 对应 NSTaggedPointerString 196 | 197 | @param to 截取终点位置 198 | @return 返回截取的字符串 199 | */ 200 | - (NSString *)safePoint_substringToIndex:(NSUInteger)to { 201 | if (to > self.length ) { 202 | return nil; 203 | } 204 | return [self safePoint_substringToIndex:to]; 205 | } 206 | 207 | 208 | 209 | /*********************************** rangeOfString:options:range:locale: ***************************/ 210 | /** 211 | 搜索指定 字符串 对应 __NSCFConstantString 212 | 213 | @param searchString 指定 字符串 214 | @param mask 比较模式 215 | @param rangeOfReceiverToSearch 搜索 范围 216 | @param locale 本地化 217 | @return 返回搜索到的字符串 范围 218 | */ 219 | - (NSRange)safe_rangeOfString:(NSString *)searchString options:(NSStringCompareOptions)mask range:(NSRange)rangeOfReceiverToSearch locale:(nullable NSLocale *)locale { 220 | if (!searchString) { 221 | searchString = self; 222 | } 223 | 224 | if (rangeOfReceiverToSearch.location > self.length) { 225 | rangeOfReceiverToSearch = NSMakeRange(0, self.length); 226 | } 227 | 228 | if (rangeOfReceiverToSearch.length > self.length) { 229 | rangeOfReceiverToSearch = NSMakeRange(0, self.length); 230 | } 231 | 232 | if ((rangeOfReceiverToSearch.location + rangeOfReceiverToSearch.length) > self.length) { 233 | rangeOfReceiverToSearch = NSMakeRange(0, self.length); 234 | } 235 | 236 | 237 | return [self safe_rangeOfString:searchString options:mask range:rangeOfReceiverToSearch locale:locale]; 238 | } 239 | 240 | 241 | /** 242 | 搜索指定 字符串 对应 NSTaggedPointerString 243 | 244 | @param searchString 指定 字符串 245 | @param mask 比较模式 246 | @param rangeOfReceiverToSearch 搜索 范围 247 | @param locale 本地化 248 | @return 返回搜索到的字符串 范围 249 | */ 250 | - (NSRange)safePoint_rangeOfString:(NSString *)searchString options:(NSStringCompareOptions)mask range:(NSRange)rangeOfReceiverToSearch locale:(nullable NSLocale *)locale { 251 | if (!searchString) { 252 | searchString = self; 253 | } 254 | 255 | if (rangeOfReceiverToSearch.location > self.length) { 256 | rangeOfReceiverToSearch = NSMakeRange(0, self.length); 257 | } 258 | 259 | if (rangeOfReceiverToSearch.length > self.length) { 260 | rangeOfReceiverToSearch = NSMakeRange(0, self.length); 261 | } 262 | 263 | if ((rangeOfReceiverToSearch.location + rangeOfReceiverToSearch.length) > self.length) { 264 | rangeOfReceiverToSearch = NSMakeRange(0, self.length); 265 | } 266 | 267 | 268 | return [self safePoint_rangeOfString:searchString options:mask range:rangeOfReceiverToSearch locale:locale]; 269 | } 270 | 271 | /*********************************** substringWithRange: ***************************/ 272 | /** 273 | 截取指定范围的字符串 对应 __NSCFConstantString 274 | 275 | @param range 指定的范围 276 | @return 返回截取的字符串 277 | */ 278 | - (NSString *)safe_substringWithRange:(NSRange)range { 279 | if (range.location > self.length) { 280 | return nil; 281 | } 282 | 283 | if (range.length > self.length) { 284 | return nil; 285 | } 286 | 287 | if ((range.location + range.length) > self.length) { 288 | return nil; 289 | } 290 | return [self safe_substringWithRange:range]; 291 | } 292 | 293 | /** 294 | 截取指定范围的字符串 对应 NSTaggedPointerString 295 | 296 | @param range 指定的范围 297 | @return 返回截取的字符串 298 | */ 299 | - (NSString *)safePoint_substringWithRange:(NSRange)range { 300 | if (range.location > self.length) { 301 | return nil; 302 | } 303 | 304 | if (range.length > self.length) { 305 | return nil; 306 | } 307 | 308 | if ((range.location + range.length) > self.length) { 309 | return nil; 310 | } 311 | return [self safePoint_substringWithRange:range]; 312 | } 313 | @end 314 | 315 | 经过下面测试代码,进行测试: 316 | 317 | // __NSCFConstantString 类型 318 | NSString *tmpConstantString = @"432423432432432432"; 319 | [tmpConstantString substringFromIndex:10000]; 320 | [tmpConstantString substringToIndex:1000]; 321 | [tmpConstantString substringWithRange:NSMakeRange(100, 10000)]; 322 | [tmpConstantString rangeOfString:nil]; 323 | 324 | // NSTaggedPointerString 类型 325 | NSString *tmpPointerString = [NSString stringWithFormat:@"4"]; 326 | [tmpPointerString substringFromIndex:10000]; 327 | [tmpPointerString substringToIndex:1000]; 328 | [tmpPointerString substringWithRange:NSMakeRange(100, 10000)]; 329 | [tmpPointerString rangeOfString:nil]; 330 | 331 | // __NSCFString 类型(备注:类似这样:[NSString stringWithFormat:@"4535435435435"]出来也是__NSCFString,因为NSMutableString初始化出来都是__NSCFString类型,所以归到NSMutableString里面) 332 | NSMutableString *tmpCFString = [NSMutableString stringWithFormat:@"4535435435435"]; 333 | [tmpCFString substringFromIndex:10000]; 334 | [tmpCFString substringToIndex:1000]; 335 | [tmpCFString substringWithRange:NSMakeRange(100, 10000)]; 336 | [tmpCFString rangeOfString:nil]; 337 | [tmpCFString appendString:nil]; 338 | 339 | // __NSArray0 类型 340 | NSArray *tmpZoroArray = [NSArray array]; 341 | tmpZoroArray[100]; 342 | [tmpZoroArray objectAtIndex:1000]; 343 | 344 | // __NSSingleObjectArrayI 类型 345 | NSArray *tmpSingleObjectArray = [NSArray arrayWithObject:@"200"]; 346 | tmpSingleObjectArray[100]; 347 | [tmpSingleObjectArray objectAtIndex:1000]; 348 | 349 | // __NSArrayI 类型 350 | NSArray *tmpArrayI = [NSArray arrayWithObjects:@"1",@"2", nil]; 351 | tmpArrayI[100]; 352 | [tmpArrayI objectAtIndex:1000]; 353 | 354 | // __NSArrayM 类型 355 | NSMutableArray *tmpMutableArrayM = [NSMutableArray arrayWithCapacity:0]; 356 | [tmpMutableArrayM objectAtIndex:1000]; 357 | [tmpMutableArrayM insertObject:nil atIndex:10000]; 358 | [tmpMutableArrayM removeObject:nil]; 359 | [tmpMutableArrayM removeObjectAtIndex:1000]; 360 | [tmpMutableArrayM removeObjectsInRange:NSMakeRange(-100, 10000)]; 361 | 362 | 363 | // __NSDictionaryM 类型 364 | NSMutableDictionary *tmpMutableDictM = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"100",@"A",@"200",@"B", nil]; 365 | [tmpMutableDictM removeObjectForKey:nil]; 366 | [tmpMutableDictM setObject:nil forKey:@"C"]; 367 | [tmpMutableDictM setObject:@"300" forKey:nil]; 368 | 369 | 像这几种操作都不会导致崩溃。 370 | 371 |    若有不足,麻烦您指出,谢谢! 372 | --------------------------------------------------------------------------------