• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

ios - `NSUserDefaults synchronize` 怎么跑得这么快?

[复制链接]
菜鸟教程小白 发表于 2022-12-13 14:28:28 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题

在我的应用程序中,我想为每个登录的用户将用户设置保存在 plist 文件中,我写了 one class called CCUserSettings它具有与 NSUserDefaults 几乎相同的接口(interface),它读取和写入与当前用户 ID 相关的 plist 文件。它可以工作,但性能很差。每次用户调用 [[CCUserSettings sharedUserSettings] synchronize] 时,我都会将 NSMutableDictionary(保留用户设置)写入 plist 文件,下面的代码显示 synchronize CCUserSettings 省略了一些琐碎的细节。

- (BOOL)synchronize {
    BOOL r = [_settings writeToFile:_filePath atomically:YES];
    return r;
}

我想 NSUserDefaults 应该在我们调用 [[NSUserDefaults standardUserDefaults] synchronize] 时写入文件,但是它运行得非常快,我写了一个 demo进行测试,关键部分如下,在我的 iPhone6 上运行 1000 次 [[NSUserDefaults standardUserDefaults] synchronize][[CCUserSettings sharedUserSettings] synchronize],结果是 0.45 秒与 9.16 秒相比。

NSDate *begin = [NSDate date];
for (NSInteger i = 0; i < 1000; ++i) {
    [[NSUserDefaults standardUserDefaults] setBooli%2==1) forKey"key"];
    [[NSUserDefaults standardUserDefaults] synchronize];
}
NSDate *end = [NSDate date];
NSLog(@"synchronize seconds:%f", [end timeIntervalSinceDate:begin]);


[[CCUserSettings sharedUserSettings] loadUserSettingsWithUserId"1000"];
NSDate *begin = [NSDate date];
for (NSInteger i = 0; i < 1000; ++i) {
    [[CCUserSettings sharedUserSettings] setBooli%2==1) forKey"_boolKey"];
    [[CCUserSettings sharedUserSettings] synchronize];
}
NSDate *end = [NSDate date];
NSLog(@"CCUserSettings modified synchronize seconds:%f", [end timeIntervalSinceDate:begin]);

结果显示,NSUserDefaults 比我的 CCUserSettings 快了近 20 倍。现在我开始怀疑“NSUserDefaults 真的每次我们调用 synchronize 方法时都会写入 plist 文件吗?”,但如果没有,它如何保证数据在进程退出(因为进程可能随时被杀死)?

这几天我想出了一个改进我的CCUserSettings的想法,它是mmap Memory-mapped I/O .我可以将虚拟内存映射到文件,并且每次用户调用 synchronize 时,我都会使用 NSPropertyListSerialization dataWithPropertyList:formatptions:error: 创建一个 NSData > 方法并将数据复制到该内存中,操作系统将在进程退出时将内存写回文件。但是我可能得不到好的性能,因为文件大小不固定,每次数据长度增加,我都要重新mmap一个虚拟内存,我相信这个操作很耗时。

抱歉我的冗余细节,我只是想知道 NSUserDefaults 是如何实现如此好的性能的,或者任何人都可以有一些好的建议来改进我的 CCUserSettings 吗?



Best Answer-推荐答案


在现代操作系统(iOS 8+、macOS 10.10+)上,NSUserDefaults 在您调用同步时不会写入文件。当您调用 -set* 方法时,它会向名为 cfprefsd 的进程发送一条异步消息,该进程存储新值、发送回复,然后稍后将文件写出。所有 -synchronize 所做的是等待所有未完成的消息到 cfprefsd 接收回复。

(编辑:如果愿意,您可以通过在 xpc_connection_send_message_with_reply 上设置符号断点然后设置用户默认值来验证这一点)

关于ios - `NSUserDefaults synchronize` 怎么跑得这么快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41156879/

回复

使用道具 举报

懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关注0

粉丝2

帖子830918

发布主题
阅读排行 更多
广告位

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap