真机测试的,怎么查看保存的日志
通过 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 异常 → 内部不一致
}








网友评论