iOS异常奔溃捕捉

2025-11-26  本文已影响0人  lukyy

真机测试的,怎么查看保存的日志

通过 Xcode 导出 App 沙盒 → 找到 Documents/CrashLogs**
这是真机调试查看本地文件最常用、最稳定的方式。
步骤:
1 连接你的 iPhone
2 打开 Xcode
3 点击菜单:Window → Devices and Simulators
4 选中你的 iPhone
5 在右侧选中你安装的 App
6 点击下面的按钮:Download Container…
7 打开下载到本地的 .xcappdata 文件
8 进入路径:

📌 奔溃完整汇总表

崩溃类型 最短复现示例
SIGABRT 数组越界 / KVC key 不存在 / NSAssert
SIGSEGV:访问非法内存地址 NULL 指针、野指针、C 数组越界
SIGBUS 非对齐指针访问 / mmap 文件被截断
EXC_BAD_ACCESS 访问已释放对象(use-after-free)
EXC_CRASH (SIGKILL) 主线程死循环(Watchdog)、OOM 内存爆掉
NSInternalInconsistencyException UIKit 非主线程、TableView 状态不一致、AutoLayout 冲突


⚠️ 注意:以下例子都是故意制造崩溃,用于学习和验证,请只在测试工程中使用。

✅ 1)制造 SIGABRT

(未捕获的 Objective-C 异常 / abort())

例 1:数组越界(最常见 SIGABRT)
- (void)causeSIGABRT {
    NSArray *arr = @[];
    NSLog(@"%@", arr[1]);   // ❌ 越界 → 抛出 NSRangeException → SIGABRT
}
例 2:KVC 找不到 key
- (void)causeSIGABRT_KVC {
    NSObject *obj = [NSObject new];
    [obj setValue:@"123" forKey:@"unknownKey"]; // ❌ NSUnknownKeyException → SIGABRT
}
例 3:NSAssert 失败
- (void)causeSIGABRT_Assert {
    NSAssert(NO, @"Force abort");  // ❌ 断言失败 → abort() → SIGABRT
}

✅ 2)制造 SIGSEGV

(访问非法内存地址 / segmentation fault)

例 1:访问 NULL 指针
- (void)causeSIGSEGV_NULL {
    int *p = NULL;
    *p = 10;   // ❌ 对 0x0 写 → SIGSEGV
}
例 2:野指针(访问已释放内存)
- (void)causeSIGSEGV_WildPointer {
    NSObject *obj = [NSObject new];
    __unsafe_unretained NSObject *ptr = obj;
    obj = nil;     // ARC 释放对象
    NSLog(@"%@", ptr.description);  // ❌ 访问已释放对象 → SIGSEGV
}
例 3:数组越界 C 指针
- (void)causeSIGSEGV_CArray {
    int arr[2] = {1,2};
    int x = arr[5];  // ❌ 越界读取 → SIGSEGV
    NSLog(@"%d", x);
}

✅ 3)制造 SIGBUS

(总线错误 / 非对齐访问 / mmap)

例 1:对齐错误(iOS 上可复现)
- (void)causeSIGBUS_Unaligned {
    uint32_t value = 0x12345678;
    char *p = (char *)&value;
    uint32_t *badPtr = (uint32_t *)(p + 1); // ❌ 非4字节对齐
    uint32_t x = *badPtr;                   // → SIGBUS
    NSLog(@"%u", x);
}
例 2:访问被截断的 mmap 文件
#import <sys/mman.h>

- (void)causeSIGBUS_mmap {
    NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"bus.txt"];
    NSData *d = [@"123456" dataUsingEncoding:NSUTF8StringEncoding];
    [d writeToFile:path atomically:YES];

    int fd = open([path UTF8String], O_RDONLY);
    char *addr = mmap(NULL, 1024, PROT_READ, MAP_SHARED, fd, 0);

    truncate([path UTF8String], 1);  // ❌ 截断文件
    char x = addr[10];               // 访问已被截断的映射 → SIGBUS
    NSLog(@"%c", x);
}

✅ 4)制造 EXC_BAD_ACCESS

(访问已释放对象 / use-after-free)

例 1:使用已经释放的对象(经典 BAD_ACCESS)
- (void)causeBADACCESS {
    __unsafe_unretained NSObject *obj;
    @autoreleasepool {
        NSObject *tmp = [NSObject new];
        obj = tmp;      // unsafe_unretained 指向 tmp
    }                    // tmp 被释放
    NSLog(@"%@", obj);   // ❌ 访问已释放 → EXC_BAD_ACCESS
}
例 2:Block 中捕获已释放对象
- (void)causeBADACCESS_Block {
    __unsafe_unretained NSObject *obj = [NSObject new];
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"%@", obj);  // ❌ obj 被释放 → EXC_BAD_ACCESS
    });
}

✅ 5)制造 EXC_CRASH (SIGKILL)

(进程被系统强制杀死:Watchdog、memory、越权限)
⚠️ SIGKILL 无法在同一进程捕获,CrashHandler 拿不到必须用系统日志。

例 1:主线程卡死(Watchdog Kill)
- (void)causeSIGKILL_Watchdog {
    // ⚠️ 请在真机运行,模拟器不会触发 Watchdog
    while (1) { }  // ❌ 主线程死循环 → Watchdog → SIGKILL(EXC_CRASH)
}
例 2:疯狂占用内存(Out of Memory → SIGKILL)
- (void)causeSIGKILL_OOM {
    NSMutableArray *arr = [NSMutableArray array];
    while (1) {
        [arr addObject:[NSData dataWithLength:50 * 1024 * 1024]];  
        // 持续占内存 → 内存压力 → OOM → SIGKILL
    }
}

✅ 6)制造 NSInternalInconsistencyException

(UIKit / Foundation 的内部状态不一致)

例 1:UI 不在主线程修改
- (void)causeInternalInconsistency_UIThread {
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        UILabel *lab = [UILabel new];
        lab.text = @"Hello";  // ❌ UIKit 非主线程操作 → NSInternalInconsistencyException
    });
}
例 2:UITableView 数据源不一致
- (void)causeInternalInconsistency_Table {
    UITableView *table = [[UITableView alloc] init];
    [table beginUpdates];
    // 删除 1 行,但数据源没有同步 → 内部状态不一致
    [table deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:0]]
                 withRowAnimation:UITableViewRowAnimationAutomatic];
    [table endUpdates];  // ❌ NSInternalInconsistencyException
}
例 3:AutoLayout 冲突(也可能出现)
- (void)causeInternalInconsistency_Constraint {
    UIView *v1 = [UIView new];
    UIView *v2 = [UIView new];
    [v1 addSubview:v2];

    NSLayoutConstraint *c1 = [v2.widthAnchor constraintEqualToConstant:100];
    NSLayoutConstraint *c2 = [v2.widthAnchor constraintEqualToConstant:50];
    c1.active = YES;
    c2.active = YES;  // ❌ 相互矛盾 → AutoLayout 异常 → 内部不一致
}
上一篇 下一篇

猜你喜欢

热点阅读