zoukankan      html  css  js  c++  java
  • iOS编程中的常见奔溃汇总

    大多数闪退崩溃日志的产生都是因为应用中的Bug,这种Bug的错误种类有很多,比如 

    SEGV:(Segmentation Violation,段违例),无效内存地址,比如空指针,未初始化指针,栈溢出等;

    SIGABRT:收到Abort信号,可能自身调用abort()或者收到外部发送过来的信号;

    SIGBUS:总线错误。与SIGSEGV不同的是,SIGSEGV访问的是无效地址(比如虚存映射不到物理内存),而SIGBUS访问的是有效地址,但总线访问异常(比如地址对齐问题);

    SIGILL:尝试执行非法的指令,可能不被识别或者没有权限;

    SIGFPE:Floating Point Error,数学计算相关问题(可能不限于浮点计算),比如除零操作;

    SIGPIPE:管道另一端没有进程接手数据;

    常见的崩溃原因基本都是代码逻辑问题或资源问题,比如数组越界,访问野指针或者资源不存在,或资源大小写错误等。

     
    iOS编程中的常见奔溃汇总

    1、找不到方法的实现unrecognized selector sent to instance

    2、KVC造成的crash

    3、EXC_BAD_ACCESS

    4、KVO引起的崩溃

    5、集合类相关崩溃

    6、多线程中的崩溃

    7、Socket长连接,进入后台没有关闭

    8、Watch Dog超时造成的crash

    9、后台返回NSNull导致的崩溃,多见于Java做后台服务器开发语言

    1、找不到方法的实现unrecognized selector sent to instance
    1.1、场景对应的Code
    #import "UnrecognizedSelectorVC.h"/**
     代理协议
     */
    @protocol UnrecognizedSelectorVCDelegate@optional
    - (void)notImplementionFunc;
    @end
    /**
     测试控制器的代理对象
     */
    @interface UnrecognizedSelectorVCObj : NSObject@property (nonatomic, strong) NSString *name;
    @end
    @implementation UnrecognizedSelectorVCObj
    @end
    /**
     测试控制器
     */
    @interface UnrecognizedSelectorVC ()
    @property(nonatomic, weak) iddelegate;
    @property(nonatomic, copy) NSMutableArray *mutableArray;
    @end
    @implementation UnrecognizedSelectorVC
    - (void)viewDidLoad {
        [super viewDidLoad];
        [self case1];
    }
    /**
     场景一:没有实现代理
     */
    - (void)case1 {
        UnrecognizedSelectorVCObj* obj = [[UnrecognizedSelectorVCObj alloc] init];
        self.delegate = obj;
        // 崩溃:reason: '-[UnrecognizedSelectorVCObj notImplementionFunc]: unrecognized selector sent to instance 0x2808047f0'[self.delegate notImplementionFunc];
        // 解决办法:应该使用下面的代码if ( [self.delegate respondsToSelector:@selector(notImplementionFunc)] ) {
            [self.delegate notImplementionFunc];
        }
    }
    /**
     场景二:可变属性使用copy修饰
     */
    - (void)case2 {
        NSMutableArray* array = [NSMutableArray arrayWithObjects:@1, @2, @3, nil];
        self.mutableArray = array;
        // 崩溃:reason: '-[__NSArrayI addObject:]: unrecognized selector sent to instance 0x281198a50'[self.mutableArray addObject:@4];
        // 原因:NSMutableArray经过copy之后变成NSArray
        // @property (nonatomic, copy) NSMutableArray *mArray;
        // 等同于
        // - (void)setMArray:(NSMutableArray *)mArray {
        //    _mArray = mArray.copy;
        //}
        // 解决办法:使用strong修饰或者重写set方法
    
        // 知识点:集合类对象和非集合类对象的copy与mutableCopy
        // [NSArray copy]                  // 浅复制(新的和原来的是一个array)
        // [NSArray mutableCopy]           // 深复制(array是新的,但是内容还是原来的,内容的指针没有变化)
        // [NSMutableArray copy]           // 深复制(array是新的,但是内容还是原来的,内容的指针没有变化)
        // [NSMutableArray mutableCopy]    // 深复制(array是新的,但是内容还是原来的,内容的指针没有变化)
    }
    /**
     场景三:低版本系统使用高版本API
     */
    - (void)case3 {if (@available(iOS 10.0, *)) {
            [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
                
            }];
        } else {
            // Fallback on earlier versions
        }
    }
    @end
    1.2、原因

    找不到方法iOS系统抛出异常崩溃

    1.3、解决方案:

    1、给NSObject添加一个分类,实现消息转发的几个方法

    #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(@"在 %@ 类中, 调用了没有实现的实例方法: %@ ",NSStringFromClass([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(@"在 %@ 类中, 调用了没有实现的类方法: %@ ",NSStringFromClass([self class]),NSStringFromSelector(anInvocation.selector));
    }

    2、尽量避免使用performSelector一系列方法
    3、delegate 方法调用前进行 respondsToSelector 判断,或者Release模式下使用ProtocolKit给协议添加默认实现防止崩溃,Debug模式下关闭默认实现
    4、属性和成员变量不要重名定义,合理使用 synthesize 生成属性的 setter 和 getter 方法
    5、在MRC模式下,变量的 retain 和 release 要谨慎,建议采用安全 release 方法,即 release 的对象置为 nil
    6、在.h中声明的方法如果用不到就去掉,用得到就同时在.m文件中实现
    7、可变属性(如NSMutableArray),不要使用copy修饰,或者重写set方法
    8、使用高版本的系统方法的时候做判断

    1.4、知识归纳:参考runtime 消息转发

    消息转发机制主要包含三个步骤:

    1、动态方法解析阶段

    +(BOOL)resolveClassMethod:(SEL)sel或者
    +(BOOL)resolveInstanceMethod:(SEL)sel

    2、备用接收者阶段

    - (id)forwardingTargetForSelector:(SEL)aSelector

    3、完整消息转发阶段

    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
    和
    - (void)forwardInvocation:(NSInvocation *)anInvocation
    2、KVC造成的crash
    2.1、场景对应的Code
    #import "KvcCrashVC.h"@interface KvcCrashVCObj : NSObject
    @property (nonatomic, strong) NSString *name;
    @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 case1];
    }
    /**
     场景一:对象不支持KVC
     */
    - (void)case1 {
        // reason: '[setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key key.'NSObject* obj = [[NSObject alloc]init];
        [obj setValue:@"value" forKey:@"key"];
    }
    /**
     场景二:key为nil
     */
    - (void)case2 {
        // reason: '*** -[KvcCrashVCObj setValue:forKey:]: attempt to set a value for a nil key'KvcCrashVCObj* obj = [[KvcCrashVCObj alloc]init];
        // value 为nil不会崩溃
        [obj setValue:nil forKey:@"name"];
        // key为nil会崩溃(直接写nil编译器会提示警告,更多时候我们传的是变量)
        [obj setValue:@"value" forKey:nil];
    }
    /**
     场景三:key不是object的属性产生的crash
     */
    - (void)case3 {
        // reason: '[setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key falseKey.'KvcCrashVCObj* obj = [[KvcCrashVCObj alloc]init];
        [obj setValue:nil forKey:@"falseKey"];
    }
    @end
    2.2、原因

    给不存在的key(包括key为nil)设置value

    [obj setValue:@"value" forKey:@"UndefinedKey"];
    
    [obj valueForKey:@"UndefinedKey"];
    2.3、场景:
    2.4、解决方案:
    1、如果属性存在,利用iOS的反射机制来规避,NSStringFromSelector(@selector())将SEL反射为字符串作为key。这样在@selector()中传入方法名的过程中,编译器会有合法性检查,如果方法不存在或未实现会报黄色警告。
    
    2、重写类的setValue:forUndefinedKey:和valueForUndefinedKey:
    
    -(void)setValue:(id)value forUndefinedKey:(NSString *)key{
    
    }
    -(id)valueForUndefinedKey:(NSString *)key{return nil;
    }
    3、EXC_BAD_ACCESS

    经过ARC的洗礼之后,普通的访问释放对象产生的EXC_BAD_ACCESS已经大量减少了,现在出现的EXC_BAD_ACCESS有很大一部分来自malloc的对象或者越界访问。

    #import "BadAccessCrashVC.h"#import@interface BadAccessCrashVC (AssociatedObject)
    @property (nonatomic, strong) UIView *associateView;
    @end
    @implementation BadAccessCrashVC (AssociatedObject)
    - (void)setAssociateView:(UIView *)associateView {
        objc_setAssociatedObject(self, @selector(associateView), associateView, OBJC_ASSOCIATION_ASSIGN);
        //objc_setAssociatedObject(self, @selector(associateView), associateView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    - (UIView *)associateView {return objc_getAssociatedObject(self, _cmd);;
    }
    @end
    
    @interface BadAccessCrashVC ()
    @property (nonatomic, copy)                         void(^blcok)(void);
    @property (nonatomic, weak) UIView*                 weakView;
    @property (nonatomic, unsafe_unretained) UIView*    unSafeView;
    @property (nonatomic, assign) UIView*               assignView;
    @end
    @implementation BadAccessCrashVC
    - (void)viewDidLoad {
        [super viewDidLoad];
        [self case1];
    }
    /**
     悬挂指针:访问没有实现的blcok
     */
    - (void)case1 {
        self.blcok();
    }
    /**
     悬挂指针:对象没有被初始化
     */
    - (void)case2 {
        UIView* view = [UIView alloc];
        view.backgroundColor = [UIColor blackColor];
        [self.view addSubview:view];
    }
    /**
     悬挂指针:访问的对象已经被释放掉
     */
    - (void)case3 {
        {
            UIView* view = [[UIView alloc]init];
            view.backgroundColor = [UIColor blackColor];
            self.weakView = view;
            self.unSafeView = view;
            self.assignView = view;
            self.associateView = view;
        }
        // ARC下weak对象释放后会自动置nil,因此下面的代码不会崩溃
        [self.view addSubview:self.weakView];
        // 野指针场景一:unsafe_unretained修饰的对象释放后,不会自动置nil,变成野指针,因此下面的代码会崩溃
        [self.view addSubview:self.unSafeView];
        // 野指针场景二:应该使用strong/weak修饰的对象,却错误的使用assign修饰,释放后不会自动置nil
        [self.view addSubview:self.assignView];
        // 野指针场景三:给类添加添加关联变量的时候,类似场景二,应该使用OBJC_ASSOCIATION_RETAIN_NONATOMIC修饰,却错误使用OBJC_ASSOCIATION_ASSIGN
        [self.view addSubview:self.associateView];
    }
    @end
    3.2、原因

    出现悬挂指针,对象没有被初始化,或者访问的对象被释放

    3.3、解决方案:

    1、Debug阶段开启僵尸模式,Release时关闭僵尸模式

    2、使用Xcode的Address Sanitizer检查地址访问越界

    3、创建对象的时候记得初始化

    4、对象的属性使用正确的修饰方式(strong/weak)

    5、调用block的时候,做判断

    4、KVO引起的崩溃
    4.1、场景对应的Code
    #import "KvoCrashVC.h"@interface KvoCrashVCObj : NSObject
    @property (nonatomic, strong) NSString *name;
    @end
    @implementation KvoCrashVCObj
    @end
    
    @interface KvoCrashVC ()
    @property (nonatomic, strong) KvoCrashVCObj *sObj;
    @end
    @implementation KvoCrashVC
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.sObj = [[KvoCrashVCObj alloc] init];
    //#import//    static dispatch_once_t onceToken;
    //    dispatch_once(&onceToken, ^{
    //        [XXShieldSDK registerStabilityWithAbility:(EXXShieldTypeKVO)];
    //    });
    }
    - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent *)event {
        [self func4];
    }
    /**
     观察者是局部变量,会崩溃
     */
    - (void)func1 {
        // 崩溃日志:An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.
        KvoCrashVCObj* obj = [[KvoCrashVCObj alloc] init];
        [self addObserver:obj           forKeyPath:@"view"  options:NSKeyValueObservingOptionNew
                  context:nil];
        self.view = [[UIView alloc] init];
    }
    /**
     被观察者是局部变量,会崩溃
     */
    - (void)func2 {
        // 崩溃日志:An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.
        KvoCrashVCObj* obj = [[KvoCrashVCObj alloc] init];
        [obj addObserver:self          forKeyPath:@"name" options:NSKeyValueObservingOptionNew
                 context:nil];
        obj.name = @"";
    }
    /**
     没有实现observeValueForKeyPath:ofObject:changecontext:方法:,会崩溃
     */
    - (void)func3 {
        // 崩溃日志:An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.
        [self.sObj addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:NULL];
        self.sObj.name = @"0";
    }
    /**
     重复移除观察者,会崩溃
     */
    - (void)func4 {
        // 崩溃日志:because it is not registered as an observer
        [self.sObj addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:NULL];
        self.sObj.name = @"0";
        [self.sObj removeObserver:self forKeyPath:@"name"];
        [self.sObj removeObserver:self forKeyPath:@"name"];
    }
    /**
     重复添加观察者,不会崩溃,但是添加多少次,一次改变就会被观察多少次
     */
    - (void)func5 {
        [self.sObj addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:NULL];
        self.sObj.name = @"0";
    }
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void *)context {
        NSLog(@"keyPath = %@", keyPath);
    }
    // 总结:KVO有两种崩溃
    // 1、because it is not registered as an observer
    // 2、An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.
    @end

    4.2、原因

    添加了观察者,没有在正确的时机移除

    4.3、解决方案:

    1、addObserver和removeObserver一定要成对出现,

    2、推荐使用FaceBook开源的第三方库 FBKVOController

    5、集合类相关崩溃
    5.1、场景对应的Code
    #import "CollectionCrashVC.h"@interface CollectionCrashVC ()
    @end
    @implementation CollectionCrashVC
    - (void)viewDidLoad {
        [super viewDidLoad];
        [self case4];
    }
    /**
     场景一:数组越界
     */
    - (void)case1 {
        // reason: '*** -[__NSArrayI objectAtIndex:]: index 4 beyond bounds [0 .. 2]'NSArray* array = [[NSArray alloc]initWithObjects:@1, @2, @3, nil];
        NSNumber* number = [array objectAtIndex:4];
        NSLog(@"number = %@", number);
    }
    /**
     场景二:向数组中添加nil元素
     */
    - (void)case2 {
        // reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'NSMutableArray* array = [[NSMutableArray alloc]initWithObjects:@1, @2, @3, nil];
        [array addObject:nil];
    }
    /**
     场景三:数组遍历的时候使用错误的方式移除元素
     */
    - (void)case3 {
        NSMutableArray* array = [NSMutableArray array];
        [array addObject:@1];
        [array addObject:@2];
        [array addObject:@3];
        [array addObject:@4];
        // 不崩溃
        [array enumerateObjectsUsingBlock:^(NSNumber * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {if (obj.integerValue == 1) {
                [array removeObject:obj];
            }
        }];
        // 崩溃,reason: '*** Collectionwas mutated while being enumerated.'for (NSNumber* obj in array) {if (obj.integerValue == 2) {
                [array removeObject:obj];
            }
        }
        //    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        //        self.view.backgroundColor = [UIColor blueColor];
        //    });
    }
    /**
     场景四:使用setObject:forKey:向字典中添加value为nil的键值对,推荐使用KVC的setValue:nil forKey:
     */
    - (void)case4 {
        NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
        [dictionary setObject:@1 forKey:@1];
        // 不崩溃:value为nil,只会移除key对应的键值对
        [dictionary setValue:nil forKey:@1];
        // 崩溃:reason: '*** -[__NSDictionaryM setObject:forKey:]: object cannot be nil (key: 1)'[dictionary setObject:nil forKey:@1];
    }
    @end
    5.2、原因

    越界、添加nil、多线程非原子性操作、遍历的同时移除元素

    5.3、场景:

    1、数组越界,访问下标大于数组的个数

    2、向数组中添加空数据

    3、多线程环境中,一个线程在读取,一个线程在移除

    4、一边遍历数组,一边移除数组中的元素

    5、多线程中操作可变数组(数组的扩容、访问僵尸对象)

    5.4、解决方案:

    1、给集合类添加category重写原来的方法,在内部做判断

    2、使用Runtime把原来的方法替换成自定义的安全方法

    3、给NSMutableDictionary添加元素的时候,使用setObject:forKey:向字典中添加value为nil的键值对,推荐使用KVC的setValue:nil forKey:。[mutableDictionary setValue:nil ForKey:@"name"]不会崩溃,只是从字典中移除name键值对。

    4、因为NSMutableArray、NSMutableDictionary不是线程安全的,所以在多线程环境下要保证读写操作的原子性,使用 加锁 、信号量 、GCD串行队列 、GCD栅栏dispatch_barrier_async、CGD组的dispatch_group_enter和dispatch_group_leave

    6、多线程中的崩溃
    6.1、场景对应的Code
    #import "ThreadCrashVC.h"@interface ThreadCrashVC ()
    @property (nonatomic, strong) NSMutableArray *array;
    @end
    
    @implementation ThreadCrashVC
    - (void)viewDidLoad {
        [super viewDidLoad];
    }
    - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent *)event {
        [self case1];
    }
    /**
     dispatch_group_leave比dispatch_group_enter执行的次数多
     */
    - (void)case1 {
        // 崩溃:Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1054f6348)
        dispatch_group_t group = dispatch_group_create();
        dispatch_group_leave(group);
    }
    /**
     在子线程更新UI
     */
    - (void)case2 {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            self.view.backgroundColor = [UIColor redColor];
        });
    }
    /**
     多个线程同时释放一个对象
     */
    - (void)case3 {   
        // ==================使用信号量同步后不崩溃==================
        {
            dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
            __block NSObject *obj = [NSObject new];
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{while (YES) {
                    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
                    obj = [NSObject new];
                    dispatch_semaphore_signal(semaphore);
                }
            });while (YES) {
                dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
                obj = [NSObject new];
                dispatch_semaphore_signal(semaphore);
            }
        }
        // ==================未同步则崩溃==================
        {
            __block NSObject *obj = [NSObject new];
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{while (YES) {
                    obj = [NSObject new];
                }
            });while (YES) {
                obj = [NSObject new];
            }
        }
    }
    /**
     多线程中的数组扩容、浅复制
     扩容:数组的地址已经改变,报错was mutated while being enumerated
     浅复制:访问僵尸对象,报错EXC_BAD_ACCESS
     
     // 知识点:集合类对象和非集合类对象的copy与mutableCopy
     // [NSArray copy]                  // 浅复制
     // [NSArray mutableCopy]           // 深复制
     // [NSMutableArray copy]           // 深复制
     // [NSMutableArray mutableCopy]    // 深复制
     
     参考:
     [Swift数组扩容原理](https://bestswifter.com/swiftarrayappend/)
     [戴仓薯](https://juejin.im/post/5a9aa633518825556a71d9f3)
     */
    -(void)case4 {
        {
            NSArray *array = @[@[@"a", @"b"], @[@"c", @"d"]];
            NSArray *copyArray = [array copy];
            NSMutableArray *mCopyArray = [array mutableCopy];
            NSLog(@"array = %p,copyArray = %p,mCopyArray = %p", array, copyArray, mCopyArray);
        }
        {
            NSMutableArray *array = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
            NSArray *copyArray = [array copy];
            NSMutableArray *mCopyArray = [array mutableCopy];
            NSLog(@"array = %p,copyArray = %p,mCopyArray = %p", array, copyArray, mCopyArray);
        }
        
        dispatch_queue_t queue1 = dispatch_queue_create("queue1", 0);
        dispatch_queue_t queue2 = dispatch_queue_create("queue2", 0);
        
        NSMutableArray* array = [NSMutableArray array];
        
        dispatch_async(queue1, ^{while (true) {if (array.count < 10) {
                    [array addObject:@(array.count)];
                } else {
                    [array removeAllObjects];
                }
            }
        });
        
        dispatch_async(queue2, ^{while (true) {
                // case 1:数组扩容for (NSNumber* number in array) {
                  NSLog(@"%@", number);
                }
                // case 2:数组扩容
                NSArray* immutableArray = array;for (NSNumber* number in immutableArray) {
                  NSLog(@"%@", number);
                }
                // case 3:浅复制 在 [NSArray copy] 的过程,
                // copy 方法内部调用initWithArray:range:copyItems: 时
                // 数组被另一个线程清空,range 不一致导致抛出 exception
                NSArray* immutableArray1 = [array copy];for (NSNumber* number in immutableArray1) {
                    NSLog(@"%@", number);
                }
                // case 4:浅复制 数组内的对象被其他线程释放,访问僵尸对象
                NSArray* immutableArray2 = [array mutableCopy];for (NSNumber* number in immutableArray2) {
                    NSLog(@"%@", number);
                }
            }
        });
    }
    @end

    6.2、原因

    死锁、子线程中更新UI、多个线程同时释放一个对象

    6.3、场景

    1、在子线程中更新UI

    2、dispatch_group crash,dispatch_group_leave的次数比dispatch_group_enter次数多。参考:iOS疑难问题排查之深入探究dispatch_group crash

    3、多线程下非线程安全类的使用,如NSMutableArrayNSMutableDictionary。NSCache是线程安全的。

    4、数据缓存到磁盘和读取。

    6.4、解决方案:

    多线程遇到需要同步的时候,加锁,添加信号量等进行同步操作。一般多线程发生的Crash,会收到SIGSEGV信号,表明试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据。

    7、Socket长连接,进入后台没有关闭

    当服务器close一个连接时,若client端接着发数据。根据TCP协议的规定,会收到一个RST响应,client再往这个服务器发送数据时,系统会发出一个SIGPIPE信号给进程,告诉进程这个连接已经断开了,不要再写了。而根据信号的默认处理规则,SIGPIPE信号的默认执行动作是terminate(终止、退出),所以client会退出。

    长连接socket或重定向管道进入后台,没有关闭导致崩溃的解决办法:

    7.1、解决方案:

    • 方法一:1、切换到后台是,关闭长连接和管道,回到前台重新创建。

    • 方法二:2、使用signal(SIGPIPE,SIG_IGN),将SIGPIP交给系统处理,这么做将SIGPIPE设为SIG_IGN,使客户端不执行默认操作,即不退出。

    8、Watch Dog超时造成的crash

    主线程执行耗时操作,导致主线程被卡超过一定时间。一般异常编码是0x8badf00d,表示应用发生watch dog超时而被iOS终止,通常是应用花费太多的时间无法启动、终止或者响应系统事件。

    8.1、解决方案:

    主线程只负责更新UI和事件响应,将耗时操作(网络请求、数据库读写等)异步放到后台线程执行。

    9、后台返回NSNull导致的崩溃,多见于Java做后台服务器开发语言

    9.1、场景对应的Code

    • NULL:用于普通类型,例如NSInteger

    • nil:用于OC对象(除了类这个对象),给nil对象发送消息不会crash

    • Nil:用于Class类型对象的赋值(类是元类的实例,也是对象)

    • NSNull:用于OC对象的站位,一般会作为集合中的占位元素,给NSNull对象发送消息会crash的,后台给我们返回的就是NSNull对象

    9.2、解决方法

    利用消息转发。参考:NullSafe。当我们给一个NSNull对象发送消息的话,可能会崩溃(null是有内存的),而发送给nil的话,是不会崩溃的。

    10、在iOS中捕获异常信息

    崩溃主要是由于 Mach 异常、Objective-C 异常(NSException)引起的,同时对于 Mach 异常,到了 BSD层会转换为对应的 Signal 信号,那么我们也可以通过捕获信号,来捕获 Crash 事件。针对 NSException 可以通过注册 NSUncaughtExceptionHandler 捕获异常信息。



    作者:单线程Jack
    链接:https://www.jianshu.com/p/74247ba1393f

  • 相关阅读:
    CentOS安装按进程实时统计流量情况工具NetHogs笔记
    修改centos地址连接为自动连接
    优秀博客主推荐链接
    idea制动补全返回值变量快捷键
    mongodb系列之--分片的原理与配置
    Mongodb系列之--mongodb的启动与关闭
    mongodb系列之---副本集配置与说明
    mongodb系列之--mongodb 主从配置与说明
    go 语言学习
    php模拟post与get请求
  • 原文地址:https://www.cnblogs.com/wuzm/p/12863176.html
Copyright © 2011-2022 走看看