Swift 4中向UserDefaults存储[String]数组时应用崩溃冻结
解决Swift写入[String]数组到UserDefaults导致启动冻结的问题
看起来你在混编Objective-C和Swift的项目里,遇到了一个挺奇怪的问题:用OC往UserDefaults存字符串数组完全正常,但用Swift存[String]数组时,应用直接启动冻结,还没错误信息对吧?我来帮你一步步排查可能的原因和解决方案。
可能的原因分析
首先,Swift的[String]桥接到OC其实是NSArray<NSString *>,理论上和OC直接存的数组是兼容的,那问题大概率出在混编时的线程竞态、初始化时机或者桥接细节上:
- 你在AppDelegate里先通过OC写入了同一个key
test,紧接着又调用Swift方法再次写入,可能引发UserDefaults内部的竞态锁死; - 启动早期(比如
application:didFinishLaunchingWithOptions:阶段)调用UserDefaults写入,可能和系统的初始化逻辑冲突; - 虽然你的例子里是纯字符串数组,但不排除隐式桥接时的细微差异导致的问题。
逐步解决方案
1. 先排除同Key的竞态冲突
先注释掉OC代码里的这一行:
// [appSettings setObject:array forKey:@"test"]; ---> 暂时注释掉
然后只保留Swift里的写入逻辑,看看应用还会不会冻结。如果没问题了,说明是同一个key被OC和Swift同时写入导致的冲突,这种情况下可以调整写入时机,比如让其中一方延迟写入。
2. 改用异步写入避免主线程阻塞
启动时的UserDefaults操作如果卡在主线程,很容易导致冻结,试试把Swift的写入放到异步队列:
@objc class func appSettings(settings:UserDefaults) { let swiftArray = ["Test"] DispatchQueue.main.async { settings.set(swiftArray, forKey: "test") // 临时加上synchronize(虽然官方不推荐,但可以用来验证) settings.synchronize() } }
3. 手动桥接为OC数组再存储
如果隐式桥接有问题,试试手动把Swift数组转成NSArray再存:
@objc class func appSettings(settings:UserDefaults) { let swiftArray = ["Test"] let ocCompatibleArray = swiftArray as NSArray settings.set(ocCompatibleArray, forKey: "test") }
4. 检查UserDefaults实例的一致性
确保你传入Swift方法的settings确实是standardUserDefaults实例,也可以直接用Swift的标准写法:
@objc class func appSettings(settings:UserDefaults) { let swiftArray = ["Test"] UserDefaults.standard.set(swiftArray, forKey: "test") }
调试建议
启动冻结时,Xcode的调用栈是最好的排查工具:
- 当应用冻结时,点击Xcode调试栏的「Pause」按钮;
- 打开Debug Navigator(左侧面板的小虫子图标),查看主线程的调用栈,看是不是卡在UserDefaults的某个内部方法里,这能帮你定位具体是锁死还是其他问题。
另外,检查项目里有没有监听NSUserDefaultsDidChangeNotification的代码,会不会存在循环触发的情况,导致死锁。
内容的提问来源于stack exchange,提问作者Trichophyton
相关产品推荐
相关产品推荐

