iOS UserDefaults 落后于保存的内容
Posted
技术标签:
【中文标题】iOS UserDefaults 落后于保存的内容【英文标题】:iOS UserDefaults falls behind saved content 【发布时间】:2018-09-21 15:49:13 【问题描述】:这种情况有点过于复杂,无法用语言来描述,所以我创建了一个最小的演示项目供您下载和运行:
https://github.com/mattneub/DefaultsDemo
您将需要 Xcode 10 进行测试。这是项目运行时的样子:
项目代码似乎有很多不必要的混乱,但那是因为我已经包含了我的 real 应用程序(纸牌游戏)中的最少材料来重现我的问题'我看到了。有一副卡片和卡片布局,想法是当用户单击主页按钮时,我们会收到应用程序将退出活动的通知,我们将卡片组和卡片布局保存到 UserDefaults 中。当我们重新启动时,我们会检索牌组和卡牌布局,然后用户就可以继续玩了。
但它不能正常工作,我将解释。而实际上测试看现象很简单:
在模拟器上运行项目。
按三到五次左右随机播放按钮。 (如果你的牌开始用完了,请点击 New Deck 按钮。但在我的测试中,这通常不是必需的。)
点击模拟器上的主页按钮。这使我们保存到 UserDefaults。查看 Xcode 控制台;它告诉您有许多卡片在刚刚保存到 UserDefaults 中的卡片组中。记住那个号码!
返回 Xcode,停止项目并再次运行它,从第 1 步重新开始。当我们启动时,您会被告知牌组中有多少张卡片是刚刚从 UserDefaults 中检索到的。
不断重复这四个步骤。发生在我身上的是,大约两三个周期后,第 4 步中的数字与第 3 步中的数字不同。我们没有从 UserDefaults 中返回我们刚才保存到 UserDefaults 中的同一套牌!
此外,关于这个错误的数字,我可以多说几句:它是我们在较早的场合保存到 UserDefaults 中的牌组中的牌张数。就好像 UserDefaults 已经以某种方式悄无声息地损坏并停止接受新版本的套牌。
为了说明,我刚刚清理了模拟器并打开了项目,我将运行它并告诉你我在控制台中看到了什么(用 cmets 解释我做了什么):
81 // launch
65
starting fresh 65
62 // shuffle
59 // shuffle
56 // shuffle
saving 56 // Home button
好的,让我们再次从 Xcode 启动:
retrieving 56 // launch
53 // shuffle
50 // shuffle
47 // shuffle
44 // shuffle
saving 44 // Home button
好的,让我们再次从 Xcode 启动:
retrieving 56 // launch
这就是错误!我们落后了;我们正在从上一个存档中取回套牌,而不是我们刚刚进行的存档中的套牌。 (我实际上可以通过打印牌组来证明这一点;它有一个description
属性就是为了这个目的,我实际上可以看到这是之前保存的牌组。)
所以问题是:为什么?我知道如何解决它;保存到文件而不是 UserDefaults。但我想知道导致这个问题的 UserDefaults 是怎么回事。我怀疑我保存到 UserDefaults 中的一个对象会导致某种静默损坏,但我不明白这是怎么回事,因为它们只是 Data 对象。
(顺便说一句,调用synchronize
不会改变任何事情,并且在任何情况下,它都会根据标题被弃用,尽管尚未正式如此。)
【问题讨论】:
可能就是这样。由于UserDefaults
是异步保存的,可能需要等待一两分钟才能重新运行应用程序。我只是看了你的代码。在willResignActiveNotification
块中设置deckArchive
后尝试调用UserDefaults.standard.synchronize()
。也许这可以解决它?
这里的行为相同。这很可能是一个时间问题(甚至可能是一个错误),它破坏了更新默认数据库的工作流程。使用synchronize()
强制更新并在重新启动应用程序之前等待几秒钟似乎可以解决问题。错误是否也出现在设备上?
@Pranay 我应该提到调用synchronize
不会改变任何东西,并且它已被弃用(参见标题)。
@matt 啊!我很抱歉。我不知道它已被弃用。尽管如此,这似乎是一个非常奇怪的问题。
@vadian 是的,在设备上也是如此。
【参考方案1】:
我将建议整个项目是一个红鲱鱼,问题在于您的测试程序。
我推测 UserDefaults 保存速度很慢:对 UserDefaults 的更改需要很长时间才能“接受”,即使在每个信号都发生了更改已发生(synchronize
已返回,didChange
通知已到达,等等)。
因此,我敢打赌,您只是 没有在点击 Home 按钮和再次运行应用程序之间留出足够的时间。要查看可能是这样,请进行以下更改:不要直接从第 3 步转到第 4 步,而是插入第 3a 步,在此您数到 10,慢慢。现在该错误不会自行显现。
(也有人会争辩说,在willResignActiveNotification
时间保存是错误的。保存时间是相关数据更改的时间!因此,在测试示例中,我们应该在每次随机播放结束时保存 -交易操作——不是在用户点击 Home 按钮时。)
【讨论】:
以上是关于iOS UserDefaults 落后于保存的内容的主要内容,如果未能解决你的问题,请参考以下文章
UserDefaults - 使用 Xcode Simulator 时保存不一致
在 UserDefaults 中保存项目数组 - iOS 12