这种情况太过复杂,无法用简单的语言来描述,因此我创建了一个最小的演示项目供您下载和运行:
https://github.com/mattneub/DefaultsDemo
您将需要Xcode 10进行测试。这是项目运行时的样子:
该项目代码似乎有很多不必要的混战,但这是因为我包含了我的 real 应用程序(纸牌游戏)中的最小内容以重现我的问题。我在看有一个纸牌和一个纸牌布局,其想法是当用户单击“主页”按钮时,我们会收到一条通知,通知该应用程序将退出活动状态,并将纸牌和纸牌布局保存到UserDefaults中。重新启动时,我们会检索套牌和纸牌布局,并且用户可以继续玩游戏。
但是,正如我将要解释的那样,它无法正常工作。实际上,测试来查看现象很简单:
在模拟器上运行项目。
按“随机播放”按钮三到五次左右。 (如果您开始用完所有卡片,请点击“ New Deck”按钮。但是在我的测试中,通常没有必要。)
在模拟器上单击“主页”按钮。这导致我们保存到UserDefaults中。查看Xcode控制台;它表明您有许多卡刚刚保存到UserDefaults中。记住那个数字!
返回Xcode,停止项目并再次运行它,从步骤1开始。在启动时,系统会告诉您刚从UserDefaults中检索到的卡中有多少张卡。
< / li>继续重复这四个步骤。我发生的事情是,在大约两个或三个周期之后,步骤4中的数字与步骤3中的数字有所不同。我们没有从UserDefaults找回刚才存储在UserDefaults中的同一卡座!
此外,对于这个错误的数字,我可以说更多:它是我们早些时候保存到UserDefaults 中的卡组中的卡数。好像UserDefaults已经以某种方式无声地损坏了并且已经停止接受平台的新版本一样。
为说明起见,我刚刚清理了模拟器并打开了项目,然后将其运行并告诉您我在控制台中看到的内容(带有注释以解释我的所作所为):
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中的一个对象引起了某种程度的无声破坏,但是我不知道怎么回事,因为它们只是数据对象。
(顺便说一句,调用synchronize
并不会改变任何东西,尽管在形式上尚未正式使用,但无论如何它都根据标头被弃用。)
答案 0 :(得分:0)
我将建议整个项目是一个红鲱鱼,问题在于您的测试过程。
我认为 UserDefaults保存缓慢:对UserDefaults进行更改仅花费很长时间才能“接受”,甚至在出现以下所有信号后 已经发生(synchronize
已返回,didChange
通知已到达,依此类推)。
因此,我敢打赌,您只是在按下“主页”按钮和再次运行应用程序之间没有足够的时间。要看到可能是这样,请进行以下更改:不要直接从第3步转到第4步,而是插上第3a步,即缓慢地计数到10。现在,该错误不会显现出来。
(也可以说在willResignActiveNotification
时保存是错误的。保存的时间就是相关数据发生变化的时间!因此,在测试示例中,我们应该在每次改组结束时保存-交易操作-不在用户点击“主页”按钮时显示。)