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

  • 相关阅读:
    WRF WPS预处理
    CVS安装
    Linux窗口最小化消失,任务栏上无法找到的解决方法
    NCARG安装配置出现error while loading shared libraries: libg2c.so.0问题额解决办法
    Netcdf安装
    Embedding R-generated Interactive HTML pages in MS PowerPoint(转)
    The leaflet package for online mapping in R(转)
    Some 3D Graphics (rgl) for Classification with Splines and Logistic Regression (from The Elements of Statistical Learning)(转)
    What does a Bayes factor feel like?(转)
    Weka算法介绍
  • 原文地址:https://www.cnblogs.com/wuzm/p/12863176.html
Copyright © 2011-2022 走看看