iOS开发过程中,会遇到各式各样的crash,影响app运行稳定性。这里做一次常见crash整理,方便后续遇到类似问题时快速解决。查看demo可访问地址:https://github.com/gurisxie/GXCommonCrash
Case:bad_access
当我们访问一些空指针或者僵尸对象问题,类似访问了野指针,会出现 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
当我们访问一个对象方法时,如果该方法没有做实现,或者入参类型非约定类型,但调用了约定类型的方法,出现 **unrecognized selector sent to instance**
的crash。
@interface GXUnRecognizedCase : NSObject
-(instancetype)initWithData:(id)data;
@end
@implementation GXUnRecognizedCase
// 未实现initWithData
@end
正常场景下,不会出现未实现的情况。但有一种情况,我们定义了协议,但是调用协议实现时,经常会遇到未实现的情况。故需要在调用实现时,先通过 respondsToSelector
进行方法判断。
Case:NSRangeException
当我们访问数组时,当索引超过数组长度,就会出现Terminating app due to uncaught exception 'NSRangeException'
crash
NSArray* arr = @[@"1", @"2"];
NSLog(@"%@", arr[2]);
当我们往数组中添加nil时,会出现 object cannot be nil
crash
NSMutableArray* arr = [NSMutableArray new];
[arr addObject:nil];
Case:当前串行队列中执行该队列的同步任务
举例来看,当我们在主线程中,启动了一个主队列的同步任务,因串行队列任务执行是串行的,导致同步任务无法分配资源执行。而当前任务一直在等待同步任务执行完毕,导致等待死锁。
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2");
});
NSLog(@"3");
});
Case:Dispatch_once出现死锁
dispatch_once一般用于单例模式,创建全局唯一类对象,方便后续调用方便。但有时因实现间的互相依赖,导致dispatch_once block执行过程中又触发了dispatch_once的调用,导致死锁。
@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 会调用 GXDispatchOnceCase导致
GXDispatchOnceDemo* demo = [[GXDispatchOnceDemo alloc] init];
NSLog(@"%@", demo);
return self;
}
@end
Case:assign修饰了引用类型
assign 等价于用 **__unsafe_unretained **,该关键字修饰对象时,不会对该对象做引用计数,和weak相似。但和weak不同的点在于,weak修饰的对象在dealloc后,会将指向该对象的所有weak指针置nil,以保证对象释放后不会出现指向该地址的野指针。
@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
网友评论