iOS 中常見 Crash 總結

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做后臺服務器開發(fā)語言

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是新的痹愚,但是內容還是原來的富岳,內容的指針沒有變化)
}
/**
 場景三:低版本系統(tǒng)使用高版本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系統(tǒng)拋出異常崩潰

1.3拯腮、解決方案:

1窖式、給NSObject添加一個分類,實現消息轉發(fā)的幾個方法

#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吨拍、使用高版本的系統(tǒng)方法的時候做判斷

1.4褪猛、知識歸納:參考runtime 消息轉發(fā)

消息轉發(fā)機制主要包含三個步驟:

1、動態(tài)方法解析階段

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

2羹饰、備用接收者階段

- (id)forwardingTargetForSelector:(SEL)aSelector

3伊滋、完整消息轉發(fā)階段

- (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的反射機制來規(guī)避乌妙,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、創(chuàng)建對象的時候記得初始化

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赂毯、多線程環(huán)境中战虏,一個線程在讀取,一個線程在移除

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不是線程安全的档插,所以在多線程環(huán)境下要保證讀寫操作的原子性慢蜓,使用 加鎖 、信號量 郭膛、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執(zhí)行的次數多
 */
- (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、多線程下非線程安全類的使用敷存,如NSMutableArray墓造、NSMutableDictionary。NSCache是線程安全的锚烦。

4觅闽、數據緩存到磁盤和讀取。

6.4涮俄、解決方案:

多線程遇到需要同步的時候蛉拙,加鎖,添加信號量等進行同步操作彻亲。一般多線程發(fā)生的Crash刘离,會收到SIGSEGV信號室叉,表明試圖訪問未分配給自己的內存, 或試圖往沒有寫權限的內存地址寫數據睹栖。

7硫惕、Socket長連接,進入后臺沒有關閉

當服務器close一個連接時野来,若client端接著發(fā)數據恼除。根據TCP協議的規(guī)定,會收到一個RST響應曼氛,client再往這個服務器發(fā)送數據時,系統(tǒng)會發(fā)出一個SIGPIPE信號給進程,告訴進程這個連接已經斷開了王财,不要再寫了舌剂。而根據信號的默認處理規(guī)則,SIGPIPE信號的默認執(zhí)行動作是terminate(終止聊浅、退出),所以client會退出餐抢。

長連接socket或重定向管道進入后臺,沒有關閉導致崩潰的解決辦法:

7.1低匙、解決方案:

  • 方法一:1旷痕、切換到后臺是,關閉長連接和管道顽冶,回到前臺重新創(chuàng)建欺抗。

  • 方法二:2、使用signal(SIGPIPE,SIG_IGN)强重,將SIGPIP交給系統(tǒng)處理绞呈,這么做將SIGPIPE設為SIG_IGN,使客戶端不執(zhí)行默認操作间景,即不退出佃声。

8、Watch Dog超時造成的crash

主線程執(zhí)行耗時操作拱燃,導致主線程被卡超過一定時間秉溉。一般異常編碼是0x8badf00d,表示應用發(fā)生watch dog超時而被iOS終止碗誉,通常是應用花費太多的時間無法啟動召嘶、終止或者響應系統(tǒng)事件。

8.1哮缺、解決方案:

主線程只負責更新UI和事件響應弄跌,將耗時操作(網絡請求、數據庫讀寫等)異步放到后臺線程執(zhí)行尝苇。

9铛只、后臺返回NSNull導致的崩潰埠胖,多見于Java做后臺服務器開發(fā)語言

9.1、場景對應的Code

  • NULL:用于普通類型淳玩,例如NSInteger

  • nil:用于OC對象(除了類這個對象),給nil對象發(fā)送消息不會crash

  • Nil:用于Class類型對象的賦值(類是元類的實例直撤,也是對象)

  • NSNull:用于OC對象的站位,一般會作為集合中的占位元素蜕着,給NSNull對象發(fā)送消息會crash的谋竖,后臺給我們返回的就是NSNull對象

9.2、解決方法

利用消息轉發(fā)承匣。參考:NullSafe蓖乘。當我們給一個NSNull對象發(fā)送消息的話,可能會崩潰(null是有內存的)韧骗,而發(fā)送給nil的話嘉抒,是不會崩潰的。

10袍暴、在iOS中捕獲異常信息

崩潰主要是由于 Mach 異常些侍、Objective-C 異常(NSException)引起的,同時對于 Mach 異常容诬,到了 BSD層會轉換為對應的 Signal 信號娩梨,那么我們也可以通過捕獲信號,來捕獲 Crash 事件览徒。針對 NSException 可以通過注冊 NSUncaughtExceptionHandler 捕獲異常信息狈定。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市习蓬,隨后出現的幾起案子纽什,更是在濱河造成了極大的恐慌,老刑警劉巖躲叼,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芦缰,死亡現場離奇詭異,居然都是意外死亡枫慷,警方通過查閱死者的電腦和手機让蕾,發(fā)現死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來或听,“玉大人探孝,你說我怎么就攤上這事∮桑” “怎么了顿颅?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長足丢。 經常有香客問我粱腻,道長庇配,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任绍些,我火速辦了婚禮捞慌,結果婚禮上,老公的妹妹穿的比我還像新娘遇革。我一直安慰自己卿闹,他們只是感情好,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布萝快。 她就那樣靜靜地躺著,像睡著了一般著角。 火紅的嫁衣襯著肌膚如雪揪漩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天吏口,我揣著相機與錄音奄容,去河邊找鬼。 笑死产徊,一個胖子當著我的面吹牛昂勒,可吹牛的內容都是我干的。 我是一名探鬼主播舟铜,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼戈盈,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了谆刨?” 一聲冷哼從身側響起塘娶,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎痊夭,沒想到半個月后刁岸,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡她我,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年虹曙,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片番舆。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡酝碳,死狀恐怖,靈堂內的尸體忽然破棺而出合蔽,到底是詐尸還是另有隱情击敌,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布拴事,位于F島的核電站沃斤,受9級特大地震影響圣蝎,放射性物質發(fā)生泄漏。R本人自食惡果不足惜衡瓶,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一徘公、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧哮针,春花似錦关面、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蛮放,卻和暖如春缩抡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背包颁。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工瞻想, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人娩嚼。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓蘑险,卻偏偏與公主長得像,于是被迫代替她去往敵國和親岳悟。 傳聞我的和親對象是個殘疾皇子佃迄,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內容

  • 1、unrecognized selector sent to instance(找不到方法)2竿音、KVC造成的cr...
    人間一流閱讀 1,624評論 0 0
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,089評論 1 32
  • 本文就捕獲iOS Crash和屎、Crash日志組成、Crash日志符號化春瞬、異常信息解讀柴信、常見的Crash五部分介紹。...
    xukuangbo_閱讀 1,571評論 0 0
  • __block和__weak修飾符的區(qū)別其實是挺明顯的:1.__block不管是ARC還是MRC模式下都可以使用宽气,...
    LZM輪回閱讀 3,284評論 0 6
  • 惰性難平萄涯, 時間是一方面的原因绪氛, 但是不應該是借口, 給自己說聲對不起涝影, 對不起枣察,拖延到最后一刻才敷衍的交作業(yè), ...
    滄海一粟隨遇而安閱讀 186評論 0 0