iOS開發(fā)過程中,會遇到各式各樣的crash,影響app運行穩(wěn)定性。這里做一次常見crash整理,方便后續(xù)遇到類似問題時快速解決。查看demo可訪問地址:https://github.com/gurisxie/GXCommonCrash
Case:bad_access
當(dāng)我們訪問一些空指針或者僵尸對象問題,類似訪問了野指針,會出現(xiàn) bad_access crash。比如多線程給同一個指針賦值,不支持ARC的對象(CGImageRef)release之后再訪問等等。
@interface GXBadAccessCase()
@property (nonatomic, strong) NSString* str;
@end
@implementation GXBadAccessCase
-(instancetype)init
{
self = [super init];
dispatch_queue_t queue = dispatch_queue_create("gx.queue", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 10000; i++) {
dispatch_async(queue, ^{
self.str = [NSString stringWithFormat:@"%@", @"123456789123456"];
});
}
return self;
}
@end
Case:UnRecognized Selecter
當(dāng)我們訪問一個對象方法時,如果該方法沒有做實現(xiàn),或者入?yún)㈩愋头羌s定類型,但調(diào)用了約定類型的方法,出現(xiàn) **unrecognized selector sent to instance**的crash。
@interface GXUnRecognizedCase : NSObject
-(instancetype)initWithData:(id)data;
@end
@implementation GXUnRecognizedCase
// 未實現(xiàn)initWithData
@end
正常場景下,不會出現(xiàn)未實現(xiàn)的情況。但有一種情況,我們定義了協(xié)議,但是調(diào)用協(xié)議實現(xiàn)時,經(jīng)常會遇到未實現(xiàn)的情況。故需要在調(diào)用實現(xiàn)時,先通過 respondsToSelector 進行方法判斷。
Case:NSRangeException
當(dāng)我們訪問數(shù)組時,當(dāng)索引超過數(shù)組長度,就會出現(xiàn)Terminating app due to uncaught exception 'NSRangeException' crash
NSArray* arr = @[@"1", @"2"];
NSLog(@"%@", arr[2]);
當(dāng)我們往數(shù)組中添加nil時,會出現(xiàn) object cannot be nil crash
NSMutableArray* arr = [NSMutableArray new];
[arr addObject:nil];
Case:當(dāng)前串行隊列中執(zhí)行該隊列的同步任務(wù)
舉例來看,當(dāng)我們在主線程中,啟動了一個主隊列的同步任務(wù),因串行隊列任務(wù)執(zhí)行是串行的,導(dǎo)致同步任務(wù)無法分配資源執(zhí)行。而當(dāng)前任務(wù)一直在等待同步任務(wù)執(zhí)行完畢,導(dǎo)致等待死鎖。
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2");
});
NSLog(@"3");
});
Case:Dispatch_once出現(xiàn)死鎖
dispatch_once一般用于單例模式,創(chuàng)建全局唯一類對象,方便后續(xù)調(diào)用方便。但有時因?qū)崿F(xiàn)間的互相依賴,導(dǎo)致dispatch_once block執(zhí)行過程中又觸發(fā)了dispatch_once的調(diào)用,導(dǎo)致死鎖。
@interface GXDispatchOnceCase : NSObject
+(instancetype)sharedInstance;
@end
@interface GXDispatchOnceDemo : NSObject
@end
@implementation GXDispatchOnceDemo
-(instancetype)init
{
self = [super init];
[GXDispatchOnceCase sharedInstance];
return self;
}
@end
@implementation GXDispatchOnceCase
+ (instancetype)sharedInstance
{
static dispatch_once_t onceToken;
static GXDispatchOnceCase *instance = nil;
dispatch_once(&onceToken, ^{
instance = [[GXDispatchOnceCase alloc] init];
});
return instance;
}
-(instancetype)init
{
self = [super init];
// GXDispatchOnceDemo 會調(diào)用 GXDispatchOnceCase導(dǎo)致
GXDispatchOnceDemo* demo = [[GXDispatchOnceDemo alloc] init];
NSLog(@"%@", demo);
return self;
}
@end
Case:assign修飾了引用類型
assign 等價于用 **__unsafe_unretained **,該關(guān)鍵字修飾對象時,不會對該對象做引用計數(shù),和weak相似。但和weak不同的點在于,weak修飾的對象在dealloc后,會將指向該對象的所有weak指針置nil,以保證對象釋放后不會出現(xiàn)指向該地址的野指針。
@interface GXAssignCase()
@property (nonatomic, assign) NSString* info;
@end
@implementation GXAssignCase
-(instancetype)init
{
self = [super init];
self.info = [NSString stringWithFormat:@"%@", @"asdfghjklzxcvbnm"];
dispatch_async(dispatch_get_main_queue(), ^{
// crash
NSLog(@"%@", self.info);
});
return self;
}
@end