美文网首页iOS crash
iOS常见Crash讲解

iOS常见Crash讲解

作者: 谢二九 | 来源:发表于2022-06-25 13:39 被阅读0次

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

相关文章

网友评论

    本文标题:iOS常见Crash讲解

    本文链接:https://www.haomeiwen.com/subject/sayivrtx.html