NSUserDefaults 从其他线程移除和设置对象

NSUserDefaults remove and set object from other thread

NSUserDefaults.standardUserDefaults() 我想了解为什么在从后台线程中删除一个对象然后从主线程使用相同的键添加一个对象之后,就不可能从主线程再次设置它。这是一个错误吗?或者它是否按预期工作?

    let mykey = "nsDataKeyOne"
    let stringUno:NSString = "................."
    let dataOne = stringUno.dataUsingEncoding(NSUTF8StringEncoding)!
    let stringDos:NSString = "000000000000000000"
    let dataTwo = stringDos.dataUsingEncoding(NSUTF8StringEncoding)!
    let userDefaults = NSUserDefaults.standardUserDefaults()


    userDefaults.setObject(dataOne, forKey: mykey)

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), {
        userDefaults.removeObjectForKey(mykey)
    })

    userDefaults.setObject(dataOne, forKey: mykey)

    print(userDefaults.dataForKey(mykey))  // print nil, why?


    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), {
        userDefaults.setObject(dataTwo, forKey: mykey)
        print(userDefaults.dataForKey(mykey)) // there is data

    })

不,这不是错误。很有可能 DISPATCH_QUEUE_PRIORITY_HIGH 队列 在你第二次调用 之后 userDefaults.removeObjectForKey(mykey) 已经执行了,所以它已经被在你想打印出来的时候删除。

如果将第一个 dispatch_async 更改为 dispatch_sync,您将在打印时看到数据。

简答

您得到 nil 因为指令可能按以下顺序执行

userDefaults.setObject(dataOne, forKey: mykey)
userDefaults.setObject(dataOne, forKey: mykey)
userDefaults.removeObjectForKey(mykey)
print(userDefaults.dataForKey(mike))

原因

首先,NSUserDefaults是线程安全的。所以我们可以想象,当没有另一个线程正在更改该值时,对给定键执行写操作。

这条指令执行时 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), { userDefaults.removeObjectForKey(我的钥匙) })

另一个线程开始尝试将闭包添加到全局队列。当此线程正在等待访问全局队列时,您的代码会继续执行,因此(可能)会执行此行

userDefaults.setObject(dataOne, forKey: mike)

此行会锁定 NSUserDefaults,直到 dataOne 被保存。

接下来闭包终于在主队列中,可以执行了所以

userDefaults.removeObjectForKey(mike)

最后是打印

print(userDefaults.dataForKey(mykey))