Common Crash

  1. An implementation of a method that cannot be found is unrecognized selector sent to instance
  2. Crash caused by KVC
  3. EXC_BAD_ACCESS
  4. Crash caused by KVO
  5. Collection class-related crash
  6. Crash in multithreading
  7. Socket long connection, enter the background is not closed
  8. Watch Dog crash
  9. The background returns a crash caused by NSNull

1 The implementation of the method cannot be foundunrecognized selector sent to instance

1.1 Corresponding Code

person.h

@protocol PersonDelegate <NSObject> - (void)didChangedName; @end@interface Person: NSObject // This method is not implemented in.m - (void)eatFood; @property (nonatomic, weak) id<PersonDelegate>delegate; @endCopy the code

ViewController.m

#import "ViewController.h" #import "Person.h" @interface ViewController () @property (nonatomic, strong) NSMutableArray *mutableArray1; @property (nonatomic, copy) NSMutableArray *mutableArray2; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self case4]; } - (void)case1 {/* crash1. eatFood declare unimplemented solution:.m implement eatFood method, or message */ Person * Person = [[Person alloc] init]; person.delegate = self; [person eatFood]; } - (void)case2 {/* crash2. if (person.delegate && [person.delegate respondsToSelector:@selector(didChangedName)]) { [person.delegate didChangedName]; } */ Person *person = [[Person alloc] init]; person.delegate = self; [person.delegate didChangedName]; } - (void)case3 { NSMutableArray *array = [NSMutableArray arrayWithObjects:@"1",@"2",@"3", nil]; self.mutableArray1 = array; Self. mutableArray2 = array; self.mutableArray2 = array; [self.mutablearray1 addObject:@"4"]; [self.mutabLearray1 addObject:@"4"]; -[__NSArrayI addObject:]: Unrecognized selector sent to instance 0x600002628EA0 // Cause: [NSArray addObject] [NSArray addObject] [NSArray addObject] Modify or override setter methods with strong [self.mutableArray2 addObject:@"4"]; / / the attached: //[NSArray copy] shallow copy, NSArray //[NSArray mutableCopy] deep copy, NSMutableArray NSArray //[NSMutableArray mutableCopy] deep copy, NSMutableArray} - (void)case4 { *)) { [NSTimer scheduledTimerWithTimeInterval:1 repeats:true block:^(NSTimer * _Nonnull timer) { }]; } else { // Fallback on earlier versions } }Copy the code

1.3 the reason

(Note: Sending a message to nil does not crash, but sending an unimplemented message to a non-nil object does crash)

1.4 Solution Summary

  1. Add a class to NSObject that implements methods for message forwarding
#import "NSObject+SelectorCrash.h" @implementation NSObject (SelectorCrash) - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { if ([self respondsToSelector:aSelector]) { return [self methodSignatureForSelector:aSelector]; } return [NSMethodSignature signatureWithObjCTypes:"v@:"]; } - (void)forwardInvocation:(NSInvocation *)anInvocation {NSLog(@" in %@ class, Invocation %@ instance method ", [self class], NSStringFromSelector(anInvocation. Selector)); } + (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { if ([self respondsToSelector:aSelector]) { return [self methodSignatureForSelector:aSelector]; } return [NSMethodSignature signatureWithObjCTypes:"v@:"]; } + (void)forwardInvocation:(NSInvocation *)anInvocation {NSLog(@" in %@ class, Invocation of %@ class method ", [self class], NSStringFromSelector(anInvocation. Selector)); } @endCopy the code
  1. Before the Delegate method is calleddelegate.respondsToSelectorjudge
  2. H declared methods to add implementation
  3. NSMutableArray use strong as much as possible (note data modification issues)
  4. Version determination when using system API

1.5 Runtime Message dynamic parsing and forwarding

2. Crash caused by KVC

2.1 Corresponding Code

@interface KVCCrashVCObj : NSObject @property (nonatomic, copy) NSString *nickname; @end @implementation KVCCrashVCObj - (void)setValue:(id)value forUndefinedKey:(NSString *)key { } - (id)valueForUndefinedKey:(NSString *)key { return nil; } @end @interface KVCCrashVC () @end @implementation KVCCrashVC - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor lightGrayColor]; //[self case1]; [self case2]; } - (void) case1 {/ * object does not support the KVC reason: '[0 < KVCCrashVCObj x6000008ccd30 > setValue: forUndefinedKey:] : this class is not key value coding-compliant for the key key.' */ KVCCrashVCObj *obj = [[KVCCrashVCObj alloc] init]; [obj setValue:@"value" forKey:@"key"]; } - (void)case2 {/* key set to nil reason: '*** -[KVCCrashVCObj setValue:forKey:]: attempt to set a value for a nil key' */ KVCCrashVCObj *obj = [[KVCCrashVCObj alloc] init]; [obj setValue:nil forKey:@"nickname"]; [obj setValue:@"value" forKey:nil]; } - (void)case3 {/* Pass non-existent key value Reason: '[<KVCCrashVCObj 0x6000019F3150 > valueForUndefinedKey:]: This class is not key value coding-compliant for the key key. KVCCrashVCObj rewrite - (id)valueForUndefinedKey:(NSString *)key */ KVCCrashVCObj *obj = [[KVCCrashVCObj alloc] init]; NSString *nickname = [obj valueForKey:@"key"]; } @endCopy the code

2.2 the reason

Set value to nonexistent key or nil by nonexistent key value

[obj setValue: @"value" forKey: @"undefinedKey"];
[obj setValue: @"value" forKey: nil];
[obj valueForKey: @"undifinedKey"];

Copy the code

2.3 Solutions

  1. If the attribute exists, it can be circumvented by iOS reflection,[obj setValue:@"value" forKey:NSStringFromSelector(@selector(undifinedKey))];The SEL is reflected as a string as the key, so that when the @selecor() method name is passed in, the compiler checks and warns if the method does not exist
  2. The class ofsetValue:forUndefinedKey:andvalueForUndefinedKey:

3. Crash caused by KVO

3.1 KVO knowledge review

3.1.1 KVO Parameters

KVOCrashObj* obj = [[KVOCrashObj alloc] init]; Observer: obj 2. Observed: self 3. Observed object: view 4. Context: An optional parameter that is passed along with the observation message to distinguish the observer receiving the message. In general, the observer receiving the message can be identified only by keyPath. But when the parent and subclasses all look at the same keyPath, keyPath alone cannot tell whether the message should be passed to the child or the parent. ObserveValueForKeyPath: ofObject: change: Context: to accept to the observer the self view changes * / [self addObserver: obj forKeyPath: @ "the view" options: NSKeyValueObservingOptionNew context:nil];Copy the code

3.1.2 KVO nature

How does iOS implement KVO for an object? (What is the nature of KVO?)

A. When an object uses a KVO listener, iOS changes the isa pointer to that object to point to a new Runtime subclass that has its own implementation of the set method. The set implementation internally calls the willChangeValueForKey method, the original setter implementation, didChangeValueForKey method, And internal didChangeValueForKey method will be called the listener observeValueForKeyPath: ofObject: change: context: monitoring method.

3.1 Corresponding Code

#import "KVOCrashVC.h" @interface KVOCrashObj : NSObject @property (nonatomic, copy) NSString *nickname; @end @implementation KVOCrashObj - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object Change (NSDictionary<NSKeyValueChangeKey,id> *)change context (void *)context {NSLog(@"%@ observed %@ changed ",[self class],[object class],keyPath); } @end @interface KVOCrashVC () @property (nonatomic, strong) KVOCrashObj *kvoObj; @end @implementation KVOCrashVC - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor lightTextColor]; self.kvoObj = [[KVOCrashObj alloc] init]; } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self case2]; } - (void) case1 {/ * self to observe the nickname of obj values change, the self vc did not achieve observeValueForKeyPath: ofObject: changecontext: lead to crash "reason: '<KVOCrashVC: 0x7f84dc617a20>: An -observeValueForKeyPath:ofObject:change:context: message was received but not handled. Key path: nickname Observed object: <KVOCrashObj: 0x60000268a120> Change: { kind = 1; new = ""; } Context: 0x0' */ KVOCrashObj* obj = [[KVOCrashObj alloc] init]; [self addObserver:obj forKeyPath:@"view" options:NSKeyValueObservingOptionNew context:nil]; [obj addObserver:self forKeyPath:@"nickname" options:NSKeyValueObservingOptionNew context:nil]; obj.nickname = @""; } - (void)case2 {/* Remove observer repeatedly cause crash reason: 'Cannot remove an observer <KVOCrashVC 0x7f8199912f00> for the key path "nickname" from <KVOCrashObj 0x6000004f5780> because it is not registered as an observer.' */ [self.kvoObj addObserver:self forKeyPath:@"nickname" options:NSKeyValueObservingOptionNew context:nil]; self.kvoObj.nickname = @"objc.c"; [self.kvoObj removeObserver:self forKeyPath:@"nickname"]; [self.kvoObj removeObserver:self forKeyPath:@"nickname"]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {NSLog(@"%@ observed %@ change %@ ",[self class],[object class],keyPath); } @endCopy the code

3.2 the reason

  1. Not implemented after adding observerobserveValueForKeyPath: ofObject: change: context:methods
  2. Remove observer repeatedly

3.3 Solutions

  1. The observer must implementobserveValueForKeyPath: ofObject: change: context:methods
  2. addobserverandremoveObserverThey have to come in pairs

4. EXC_BAD_ACCESS

4.1 Corresponding Code

#import "BadAccessCrashVC.h" #import <objc/runtime.h> @interface BadAccessCrashVC (AssociatedObject) @property (nonatomic, strong) UIView *associatedView; @end @implementation BadAccessCrashVC (AssociatedObject) - (void)setAssociatedView:(UIView *)associatedView { /* self: Class key of an associated object: To ensure global uniqueness, the key must be globally unique in a one-to-one correspondence with the associated object. Usually, @selector(methodName) is used as the key value: Object to be associated policy: Association_copy: equivalent to @property(atomic,copy) OBJC_ASSOCIATION_COPY_NONATOMIC: Equivalent to @property(nonatomic, copy) OBJC_ASSOCIATION_ASSIGN: Equivalent to @property(assign) OBJC_ASSOCIATION_RETAIN: Equivalent to @property(atomic, strong) OBJC_ASSOCIATION_RETAIN_NONATOMIC: Equivalent to @property(nonatomic, strong) */ objc_setAssociatedObject(self, @selector(associatedView), associatedView, OBJC_ASSOCIATION_ASSIGN); //objc_setAssociatedObject(self, @selector(associatedView), associatedView, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (UIView *)associatedView { return objc_getAssociatedObject(self, _cmd); } @end @interface BadAccessCrashVC () @property (nonatomic, copy) void(^block)(void); @property (nonatomic, weak) UIView *weakView; @property (nonatomic, unsafe_unretained) UIView *unsafeView; @property (nonatomic, assign) UIView *assignView; @end @implementation BadAccessCrashVC - (void)viewDidLoad { self.view.backgroundColor = [UIColor orangeColor]; [super viewDidLoad]; } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self case3]; } - (void)case1 {/* Thread 1: EXC_BAD_ACCESS (code=1, address=0x10) */ self.block(); } - (void)case2 {/* Suspend pointer: the object is not initialized Thread 1: EXC_BAD_ACCESS (code=1, address=0x0) */ UIView *view = [UIView alloc]; view.backgroundColor = [UIColor redColor]; [self.view addSubview:view]; } - (void)case3 { { UIView *view = [[UIView alloc]init]; view.backgroundColor = [UIColor redColor]; self.weakView = view; self.unsafeView = view; self.assignView = view; self.associatedView = view; } //addSubview:nil does not crash Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT) // Will not crash, weakView will be set to nil after arc view is released, So this line of code will not crash [self.view addSubview:self.weakView]; / / a wild pointer scene: unsafeunreatin modified object is released, will not automatically be set to nil, into a wild pointer, therefore collapse [self. View addSubview: self. UnsafeView]; / / wild pointer scene 2: should use the strong/weak modified object, but wrong to use the assign, after their release will not buy for nil [self. View addSubview: self. AssignView]; // Wild pointer scenario 3: Add link to the class variables, a similar scenario 2, should use OBJC_ASSOCIATION_RETAIN, but wrong use OBJC_ASSOCIATION_ASSIGN [self. View addSubview: self associatedView]; } @endCopy the code

4.2 the reason

Dangling pointer, accessing uninitialized object, accessing wild pointer

4.3 Solutions

  1. Debug environment on Zombie Objects, Release off
  2. Use Xcode’s Address Sanitizer to check for Address access transgressions
  3. Remember to initialize the object when you create it
  4. The modifier for the object is used correctly
  5. When a Block is called, make a judgment

The collection class crashes

5.1 Corresponding Codes

#import "CollectionCrashVC.h" @interface CollectionCrashVC () @end @implementation CollectionCrashVC - (void)viewDidLoad  { [super viewDidLoad]; self.view.backgroundColor = [UIColor yellowColor]; } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self case3]; } - (void)case1 {/* Array out of bounds Reason: '*** -[__NSArrayM objectAtIndex:]: index 3 beyond bounds [0 .. 2] */ NSMutableArray *array = [NSMutableArray arrayWithObjects:@1, @2, @3, nil]; NSNumber *number = [array objectAtIndex:3]; NSLog(@"number: %@", number); } - (void)case2 {/* Insert nil element into set reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil */ NSMutableArray *array = [NSMutableArray arrayWithObjects:@1, @2, @3, nil]; [array addObject:nil]; } - (void)case3 { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; [dict setObject:@1 forKey:@"1"]; // Does not crash, value is nil, only removes the corresponding key pair [dict setValue:nil forKey:@"1"]; // crash: '*** -[__NSDictionaryM setObject:forKey:]: object cannot be nil (key: 1)' [dict setObject:nil forKey:@"1"]; } @endCopy the code

5.2 the reason

  1. An array
  2. Add nil elements to the array
  3. Removing elements from the array while iterating through the array
  4. Multithreading operation array: array expansion, access to zombie objects
  5. The dictionarysetObject:nil forKey:@"key"

5.4 Solutions

  1. Runtime Swizzling Switch set selection method
  2. NSMutableArray is used when adding elementssetValue:forKey:, this method doesn’t crash when it adds nil to the dictionary, it just deletes the corresponding key-value pair
  3. Because NSMutableArray and NSMutableDictionary are not thread-safe, we can add locks, semaphores, GCD serial queues and GCD barriers to ensure atomization of read and write operations in multi-threaded environment

Dispatch_barrier_async, dispatch_group

6. Multithreading crashes

6.1 Corresponding Code

#import "ThreadCrashVC.h" @interface ThreadCrashVC () @end @implementation ThreadCrashVC - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor redColor]; } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self case4]; } - (void)case1 {// there are more dispatch_group_leave dispatch_group_enter dispatch_group_leave threads. EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) dispatch_group_t group = dispatch_group_create(); dispatch_group_leave(group); } - (void)case2 {//ain Thread Checker: UI API called on a background Thread: -[UIViewController view] dispatch_queue_t queue = dispatch_queue_create("com.objc.c", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue , ^{ NSLog(@"thread: %@", [NSThread currentThread]); self.view.backgroundColor = [UIColor yellowColor]; }); } - (void)case3 {dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); __block NSObject *obj = [[NSObject alloc] init]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ while (YES) { NSLog(@"dispatch_async -- 1"); dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); obj = [[NSObject alloc] init]; dispatch_semaphore_signal(semaphore); }}); while (YES) { NSLog(@"dispatch_sync -- 2"); dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); obj = [[NSObject alloc] init]; dispatch_semaphore_signal(semaphore); {__block NSObject *obj = [[NSObject alloc] init]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ while (YES) { NSLog(@"dispatch_async -- 3"); obj = [[NSObject alloc] init]; }}); while (YES) { NSLog(@"dispatch_sync -- 4"); obj = [[NSObject alloc] init]; } } } - (void)case4 { dispatch_queue_t queue1 = dispatch_queue_create("com.objc.c1", DISPATCH_QUEUE_SERIAL); dispatch_queue_t queue2 = dispatch_queue_create("com.objc.c2", DISPATCH_QUEUE_SERIAL); NSMutableArray *array = [NSMutableArray array]; dispatch_async(queue1, ^{ NSLog(@"queue1: %@", [NSThread currentThread]); while (YES) { if (array.count < 10) { [array addObject:@(array.count)]; } else { [array removeAllObjects]; }}}); dispatch_async(queue2, ^{ NSLog(@"queue2: %@", [NSThread currentThread]); While (YES) {/* Array address changed Reason: '*** Collection <__NSArrayM: 0x6000020319b0> was mutated while being enumerated.' */ for (NSNumber *number in array) { NSLog(@"queue2 forin array %@", number); } /* reason: '*** Collection <__NSArrayM: 0x600002072d60> was mutated while being enumerated.' */ NSArray *array2 = array; for (NSNumber *number in array2) { NSLog(@"queue2 forin array2 %@", number); } / * in [NSArray copy], the copy method called ` initWithArray: range: copyItem: ` NSArray is another thread to empty, range inconsistent resulting in abnormal ran out of the reason: '*** -[__NSArrayM getObjects:range:]: Range {0, 2} extends beyond bounds for empty array' Extends beyond bounds for empty array' EXC_BAD_ACCESS (code=1, address=0x754822c49fc0) */ NSArray *array3 = [array copy]; for (NSNumber *number in array3) { NSLog(@"queue2 forin array3 %@", number); } /* Thread 12, Thread 12, Thread 12, Thread 12 EXC_BAD_ACCESS (code=EXC_I386_GPFLT) */ NSArray *array4 = [array mutableCopy]; for (NSNumber *number in array4) { NSLog(@"queue2 forin array4 %@", number); }}}); } @endCopy the code

6.2 the reason

  1. Child threads refresh the UI
  2. Dispatch_group_leave than dispatch_group_enter
  3. Multiple threads simultaneously access and release the same object
  4. Accessing data in multiple threads: NSMutableArray, NSMutaleDictionary, NSCache are thread-safe

6.3 Solutions

When multithreading encounters data synchronization, it needs to lock, semaphore and other synchronization operations. Generally, when multithreading crashes, SIGSEGV will be received. Indicates an attempt to access memory that is not allocated to itself, or to write data to memory that the view does not have access to

7 Crash caused by Wathc Dog

The main thread is time-consuming operation, causing the main thread to be stuck for more than a certain time and the App to be terminated by the system. The general abnormal code is 0x8BADF00D, which usually refers to the reference that takes too long to start, terminate or respond to system events

7.1 Solution

The main thread does UI refreshes and event responses, and puts time-consuming operations (network requests, database reads) into the asynchronous thread

8 Background return NSNull causes a crash, which is common in JAVA background return

8.1 Corresponding Code

#import "NSNullCrashVC.h"

@interface NSNullCrashVC ()

@end

@implementation NSNullCrashVC

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor blueColor];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self case1];
}

- (void)case1 {
    /*
     reason: '-[NSNull integerValue]: unrecognized selector sent to instance 0x7fff8004b700'
     */
    NSNull *null = [[NSNull alloc] init];
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    [dict setValue:null forKey:@"key"];
    NSInteger integer = [[dict valueForKey:@"key"] integerValue];
}

@end
Copy the code
  • NULL: used for basic data types, such as NSInteger
  • nil: used for OC objects
  • Nil: used to assign to objects of type Class (a Class is an instance of a metaclass, which is also an object)
  • NSNull: used as a placeholder for an OC object, usually used as a placeholder element in a collection. Sending a message to an NSNull object will crash, and the background will return an NSNull object

8.2 Solution

Using message forwarding, see :NullSafe, when we send a message to an NSNull object, it will crash (null has memory), and when we send a message to a nil object, it will not crash

#import <objc/runtime.h> #import <Foundation/Foundation.h> #ifndef NULLSAFE_ENABLED #define NULLSAFE_ENABLED 1 #endif #pragma clang diagnostic ignored "-Wgnu-conditional-omitted-operand" @implementation NSNull (NullSafe) #if NULLSAFE_ENABLED - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { //look up method signature NSMethodSignature *signature = [super methodSignatureForSelector:selector]; if (! signature) { for (Class someClass in @[ [NSMutableArray class], [NSMutableDictionary class], [NSMutableString class], [NSNumber class], [NSDate class], [NSData class] ]) { @try { if ([someClass instancesRespondToSelector:selector]) { signature = [someClass instanceMethodSignatureForSelector:selector]; break; } } @catch (__unused NSException *unused) {} } } return signature; } - (void)forwardInvocation:(NSInvocation *)invocation { invocation.target = nil; [invocation invoke]; } #endif @endCopy the code

9 Crash caused by long Socket connection

When the server closes a connection, if the client continues to send data, according to the TCP protocol, the system will receive an RST response. When the client sends data to the server, the system will send a SIGPIPE signal to the process to tell the process that the connection has been disconnected and to stop writing. By default, the SIGPIPE signal executes terminate, so the client exits

Long-connect sockets or redirect pipes into the background, no more than a crash solution

9.1 Solution

  1. When switching to the background, close long connections and pipes and go back to the foreground to recreate
  2. Use signal (SIGPIPE, SIG_IGN) to pass SIGPIP to the system for processing. This sets SIGPIPE to SIG_IGN so that the client does not perform the default action, that is, does not exit

10. Exception catching

Before a program crashes, crash information is captured and reported for analysis

10.1 the principle

  1. OC class exception: NSException is caused by THE OC code crash. We could start by NSGetUncaughtExceptionHandler saved previously registered exception handler, then through NSSetUnCaughtExceptionHandler set up our own exception handler, we don’t monitor, needs to be set back to the principle of the exception handler, In our own uncaughtHandleException handler, we need to call the original handler manually
  2. Signal is an exception thrown by the iOS low-level Mach Signal exception after it is converted. Since it is a posiX compliant exception, we can also register the corresponding Signal through sigAction function
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { / / OC is captured in layers of exception, NSUncaughtExceptionHandler capture exception information through registration NSSetUncaughtExceptionHandler (& uncaughtExceptionhandler); // This is an error that can not be handled by the Unix standard Signal. This error can not be handled by the Unix standard Signal. Register SIGABRT, SIGBUS, SIGSEGV and other signal handlers. signal(SIGSEGV, handleSignal); return YES; } static void uncaughtExceptionhandler (NSException *exception) {NSArray *stackArray = [exception callStackSymbols]; NSString *reason = [exception reason]; NSString *name = [exception name]; NSString *exceptionInfo = [NSString stringWithFormat:@"Exception name: %@\nException reason: %@\nException stack: %@", name, reason, stackArray]; NSLog(@" App Delegate exception message: %@", exceptionInfo); / / stored locally, next time when start uploading NSMutableArray * temArray = [NSMutableArray arrayWithArray: stackArray]; [temArray insertObject:reason atIndex:0]; [exceptionInfo writeToFile:[NSString stringWithFormat:@"%@/DOcuments/error.log", NSHomeDirectory()] atomically:YES encoding:NSUTF8StringEncoding error:nil]; } static void handleSignal(int sig) { }Copy the code

reference

Summary of common crashes in iOS

IOS View and export project run logs

IOS performance optimization i. Crash monitoring and anti-crash processing

Understand the iOS exception types