Cross-border Crash processing experience for iOS Arrays
Let's first take a look at the possible cross-border Crash array;
-(Void) tableView :( UITableView *) tableView didSelectRowAtIndexPath :( NSIndexPath *) indexPath {WelfareItem * item = [_ performancearray objectAtIndex: indexPath. row]; // possibly out-of-bounds. You will use [_ performancearray removeAllObjects] During the pull-down refresh process. When you click a cell, Crash will be generated.}-(UITableViewCell *) tableView :( UITableView *) tableView cellForRowAtIndexPath :( NSIndexPath *) indexPath {WelfareItem * item = _ performancearray [indexPath. row]; // possibly cross-border. [tableView reloadData] is used in two places; the last one has [_ performancearray removeAllObjects]; Crash}
The above code may be out of bounds; Crash may not be repeated, and the issued App will always receive several Crash; the Code to solve this problem is also very simple:
-(Void) tableView :( UITableView *) tableView didSelectRowAtIndexPath :( NSIndexPath *) indexPath {WelfareItem * item = nil; if (indexPath. row <[_ performancearray count]) {// no matter how high your skill is, you sometimes forget to add item = [_ performancearray objectAtIndex: indexPath. row] ;}}- (UITableViewCell *) tableView :( UITableView *) tableView cellForRowAtIndexPath :( NSIndexPath *) indexPath {WelfareItem * item = nil; if (indexPath. row <[_ performancearray count]) {item = [_ performancearray objectAtIndex: indexPath. row] ;}}
The problem arises again. No matter how high your martial arts are, you may forget to add them. So we have to find a way to create an enemy. I thought of replacing the objectAtIndex method with Runtime. The Code is as follows:
/*! @ Category @ abstract NSObject's Category */@ interface NSObject (Util )/*! @ Method swizzleMethod: withMethod: error: @ abstract Replace the instance method @ param oldSelector the method to be replaced @ param newSelector the actual replacement method @ param error errors, if there is no error: nil */+ (BOOL) swizzleMethod :( SEL) originalSelector withMethod :( SEL) swizzledSelector error :( NSError **) error; @ end # import "NSObject + Util. h "# import
@ Implementation NSObject (Util) + (BOOL) swizzleMethod :( SEL) originalSelector withMethod :( SEL) warn error :( NSError **) error {Method originalMethod = compile (self, originalSelector ); if (! OriginalMethod) {NSString * string = [NSString stringWithFormat: @ "% @ class not found % @ method", NSStringFromClass ([self class]), NSStringFromSelector (originalSelector)]; * error = [NSError errorWithDomain: @ "NSCocoaErrorDomain" code:-1 userInfo: [NSDictionary dictionaryWithObject: string forKey: Counter]; return NO;} Method swizzledMethod = consume (self, swizzledSelector); if (! SwizzledMethod) {NSString * string = [NSString stringWithFormat: @ "% @ class not found % @ method", NSStringFromClass ([self class]), NSStringFromSelector (swizzledSelector)]; * error = [NSError errorWithDomain: @ "NSCocoaErrorDomain" code:-1 userInfo: [NSDictionary dictionaryWithObject: string forKey: Counter]; return NO;} if (class_addMethod (self, originalSelector, method_getImplementation (swizzledMethod), sums (swizzledMethod) {sums (self, sums, sums (originalMethod), sums (originalMethod);} else {extract (originalMethod, swizzledMethod );} return YES;} @ end @ implementation NSArray (ErrerManager) + (void) load {static dispatch_once_t onceToken; dispatch_once (& onceToken, ^ {@ autoreleasepool {[objc_getClass ("_ NSArrayI") swizzleMethod: @ selector (objectAtIndex :) withMethod: @ selector (swizzleObjectAtIndex :) error: nil]; [objc_getClass ("_ NSArrayM") swizzleMethod: @ selector (objectAtIndex :) withMethod: @ selector (swizzleObjectAtIndex :) error: nil] ;}});}-(id) swizzleObjectAtIndex :( NSUInteger) index {if (index <self. count) {return [self swizzleObjectAtIndex: index];} NSLog (@ "% @ ", self); return nil; // return nil} @ end
With the above Code, we use [_ performancearray objectAtIndex: indexPath. row] to avoid cross-border Crash. Cross-border
It will return nil; it seems to be a good solution; send the app, and we get a Crash that is several times higher than before (the cross-border Crash is gone, new Crash); Crash is as follows
1 tbreader 0x002b93e9 tbreader + 20981532 libsystem_platform.dylib 0x33a66873 _sigtramp + 343 libsystem_blocks.dylib 0x33941ae1 _Block_release + 2164 libobjc.A.dylib 0x333c11a9 + 4045 CoreFoundation 0x25ba23a9 _CFAutoreleasePoolPop + 166 UIKit 0x2912317f + 427 CoreFoundation 0x25c565cd + 208 CoreFoundation 0x25c53c8b + 2789 CoreFoundation 0x25c54093 + 91410 CoreFoundation 0x25ba2621 CFRunLoopRunSpecific + 47611 CoreFoundation 0x25ba2433 CFRunLoopRunInMode + 10612 GraphicsServices 0x2cf0a0a9 GSEventRunModal + 13613 UIKit 0x2918c809 UIApplicationMain + 1440
This Crash occurs above iOS7 (including iOS7). The key is that no user feedback is provided. Crash is several times higher than other users. This is still rare, we can't reproduce the test. After a week of test, we finally reproduced the same Crash. This is the case. We replaced the objectAtIndex method with the input, and press the Home key on the keyboard to make the Crash happen; this method is not enough. You can only find another policy. The code for adding an extension method to the array is as follows:
@ Interface NSArray (SHYUtil )/*! @ Method objectAtIndexCheck: @ abstract check whether cross-border and NSNull are returned If nil @ result returns the object */-(id) objectAtIndexCheck :( NSUInteger) index; @ end # import "NSArray + SHYUtil. h "@ implementation NSArray (SHYUtil)-(id) objectAtIndexCheck :( NSUInteger) index {if (index> = [self count]) {return nil;} id value = [self objectAtIndex: index]; if (value = [NSNull null]) {return nil;} return value;} @ endChange the previous Code WelfareItem * item = [_ performancearray objectAtIndex: indexPath. row] To WelfareItem * item = [_ performancearray objectAtIndexCheck: indexPath. row. In this way, the array out-of-bounds-[_ NSArrayI objectAtIndex:]: index 100 beyond bounds [0 .. 1] 'error can be completely solved.