前言
字节团队最近分享的 iOS 稳定性问题治理:卡死崩溃监控原理及最佳实践 提到:NSUserDefaults 底层实现中存在直接或者间接的跨进程通信,在主线程同步调用容易发生卡死。
随之而来的问题就是:NSUserDefaults 还能用吗?
经过对底层分析后,笔者的研究结论是:可以在理解 NSUserDefaults 的特性后再使用。
一、NSUserDefaults 是什么?
NSUserDefaults 是 iOS 开发者常用的持久化工具,通常用于存储少量的数据
示例:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:@"酷酷的哀殿" forKey:@"key"];
二、NSUserDefaults 的特性是什么?
根据本文后续的测试,我们可以发现 NSUserDefaults 共计以下 3 个特性:
- 多线程安全
- 内存级别缓存
- 写操作会触发 xpc 通信
三、 NSUserDefaults 是如何保证多线程安全的?
NSUserDefaults 内部在读写时,会通过锁 lock 保证读写安全
可以通过 b os_unfair_lock_lock 设置断点
四、NSUserDefaults 的性能怎么样?
虽然 NSUserDefaults 是磁盘持久化存储,但是因为缓存的存在,所以,不会频繁的进行 磁盘 I/O
我们唯一需要考虑的因素避免数据过多导致内存压力过大
五、NSUserDefaults 触发 xpc 的场景是什么?
NSUserDefaults 与 如何监控 iOS 的启动耗时 提到的渲染过程类似,同样依赖 xpc 进行跨进程通信。
下面,我们通过添加合适的断点对相关流程进行简单的介绍
添加调试断点
xpc_connection_send_message_with_reply_sync 会锁住当前线程
准备测试代码
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:@"酷酷的哀殿1" forKey:@"key"]; //xpc_connection_send_message_with_reply_sync
[defaults setObject:@"酷酷的哀殿2" forKey:@"key"]