美文网首页SwiftiOS DeveloperiOS-Dev
弃用UserDefaults 中的 synchronize()

弃用UserDefaults 中的 synchronize()

作者: LimChihi | 来源:发表于2017-04-04 17:21 被阅读1494次

    注意

    在连续大量的写入数据的时候杀掉程序,会丢失数据,但这种写入,不应该用UserDefaults。

    前言

    在看没故事的桌同学的一篇Swift里我用这个姿势写UserDefaults的时候,评论下面有人说不必调用synchronize(),而在以前我们习惯的用写法都是设置一个Value便synchronize()一下,来确保数据被保存下来。便随手写了一个小Demo来验证这个问题。

    Xcode and Swift Version

    • Xcode Version 8.2.1

    • Swift 3.0

    Demo

    我设置了两个UIButton 和一个UILabel

    @IBOutlet weak var tipsLabel: UILabel!
    
    @IBAction func setAction(_ sender: UIButton) {
        UserDefaults.standard.set("LimChihi", forKey: "Name")
        fatalError()
    }
    
    @IBAction func readAction(_ sender: UIButton) {
        let info = UserDefaults.standard.value(forKey: "Name") as? String
        tipsLabel.text = info ?? "nil"
    }
    

    第一个setAction用来设置值,然后使用fatalError()来使App在设置完成后立马crash掉,来模拟最极端的情况。

    第二个readAction 用来读取值,并显示在tipsLabel上,如果为空则自动设为"nil"

    结果

    我进行了两次实验,第一次设置值后,即使crash掉,App仍然能够成功读取设置的值。说明在初次设置的时候,不使用synchronize()是完全没有问题的。

    第二次,我修改了设置的Value,先读取了第一次我存储的值(没有问题),然后重新存储了新的Value(也是存储完立即crash掉),最后读取的时候显示的是新修改的Value。说明修改一个已经存在的值,不使用synchronize()也是完全没有问题的。

    最后Apple关于synchronize()的文档里面有这样一段话

    synchronize is deprecated and will be marked with the NS_DEPRECATED macro in a future release.

    所以,直接弃用这个浪费性能方法吧。

    更新

    因为我的方法可能缺少一些更加极端的条件,所以我又做了一次测试。

    override func viewWillAppear(_ animated: Bool) {
        
        DispatchQueue.global().async { self.test() }
        DispatchQueue.global().async { self.test() }
        DispatchQueue.global().async { self.test() }
        DispatchQueue.global().async { self.test() }
        DispatchQueue.global().async { self.test() }
        DispatchQueue.global().async { self.test() }
        DispatchQueue.global().async { self.test() }
        DispatchQueue.global().async { self.test() }
    }
    
    @IBAction func setAction(_ sender: UIButton) {
        UserDefaults.standard.set("LimChihi", forKey: "Name")
        fatalError()
    }
    @IBAction func readAction(_ sender: UIButton) {
        let str = UserDefaults.standard.value(forKey: "Name")
        print(str ?? "nil")
        
    }
    
    func test() {
        while true {
            var a = 99999999999 * 50000
            a += 33
        }
    }
    
    

    用一个简单的while死循环来模拟高CPU负荷的情况,开了8个后台线程,然后最高CPU占用率在720-780%左右,结果依然成立,设置后立刻crash,也不影响数据。

    此实验可以完全复制。


    屏幕快照 2017-04-06 下午12.29.55.png

    如果有什么更极端的条件,也可以在评论下提醒我,我再重新测试。

    相关文章

      网友评论

      • 李大戮: -synchronize is deprecated and will be marked with the NS_DEPRECATED macro in a future release. 已弃用
      • Enum:建议在高CPU占用时写数据然后立刻杀进程试试会不会丢数据。文档明确写了这个方法会被自动周期性调用,因此肯定存在窗口期丢数据风险。另外文档中还有这么一段:use this method only if you cannot wait for the automatic synchronization (for example, if your application is about to exit) or if you want to update the user defaults to what is on disk even though you have not made any changes. 由此可见这个方法还是有适用场景的。建议测试得更严谨一点。
        小子爱搞事:@LimChihi 真机下测试,数据的确会丢失的
        Enum:@LimChihi 已经在微博回复你了,可以看我的测试程序,真机测试结果是丢数据了。
        LimChihi:你好,我重新测试了一下,CPU占用率提高到760%,数据依然没有丢失,你可以看一下我的更新。
      • 未央生:我之前一直没用这个 :+1:

      本文标题:弃用UserDefaults 中的 synchronize()

      本文链接:https://www.haomeiwen.com/subject/cpqzottx.html