iOS UserDefaults落后于已保存的内容 [英] iOS UserDefaults falls behind saved content

查看:59
本文介绍了iOS UserDefaults落后于已保存的内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这种情况太过复杂,无法用简单的语言来描述,因此我创建了一个最小的演示项目供您下载和运行:

This situation is a bit too elaborate to describe in mere words, so I've created a minimal demo project for you to download and run:

https://github.com/mattneub/DefaultsDemo

您将需要Xcode 10进行测试.这是项目运行时的样子:

You will need Xcode 10 to test. This is what the project looks like when it runs:

该项目代码似乎有很多不必要的混战,但这是因为我包含了我的 real 应用程序(纸牌游戏)中的最小内容,以重现我的问题.我看到了.有一个纸牌和一个纸牌布局,其想法是当用户单击主页"按钮时,我们会收到一条通知,通知该应用程序将退出活动状态,并将纸牌和纸牌布局保存到UserDefaults中.重新启动时,我们会检索套牌和纸牌布局,并且用户可以继续玩游戏.

The project code will appear to have quite a bit of unnecessary kerfuffle, but that is because I've included the minimum material from my real app (a card game) to reproduce the issue I'm seeing. There's a deck of cards and a layout of cards, and the idea is when the user clicks the Home button, we get a notification that the app will resign active, and we save the deck and the card layout into UserDefaults. When we relaunch, we retrieve the deck and the card layout and the user can resume playing.

但是,正如我将要解释的那样,它无法正常工作.实际上,测试来查看这种现象非常简单:

But it's not working correctly, as I shall explain. And actually testing to see the phenomenon is very simple:

  1. 在模拟器上运行项目.

  1. Run the project on the simulator.

按随机播放"按钮三到五次左右. (如果您开始用完所有卡片,请点击"New Deck"按钮.但是在我的测试中,通常没有必要.)

Hit the Shuffle button three to five times or so. (If you start to run out of cards, hit the New Deck button. But in my testing, that's not usually necessary.)

在模拟器上单击主页"按钮.这导致我们保存到UserDefaults中.查看Xcode控制台;它表明您有许多卡刚刚保存到UserDefaults中.记住那个数字!

Hit the Home button on the simulator. This causes us to save into UserDefaults. Look at the Xcode console; it tells you have many cards are in the deck that was just saved into UserDefaults. Remember that number!

返回Xcode,停止该项目,然后再次运行它,再次从步骤1开始.启动时,系统会告诉您刚从UserDefaults中检索到的卡组中有多少张卡.

Back in Xcode, stop the project and run it again, starting again at Step 1. As we launch, you are told how many cards are in the deck that was just retrieved from UserDefaults.

继续重复这四个步骤.我发生的事情是,在大约两个或三个周期之后,第4步中的数字与第3步中的数字有所不同.我们没有从UserDefaults找回刚才存储在UserDefaults中的同一卡座!

Keep repeating those four steps. What happens to me is that after about two or three cycles, the number in step 4 differs from the number in step 3. We are not getting back from UserDefaults the same deck that we saved into UserDefaults a moment ago!

此外,对于这个错误的数字,我可以说更多:它是我们早些时候保存到UserDefaults 中的卡片组中的卡数.好像UserDefaults已经以某种方式无声地损坏了,并且已经停止接受卡座的新版本一样.

Moreover, I can say something more about this wrong number: it is the number of cards in the deck that we saved into UserDefaults on some earlier occasion. It is as if UserDefaults has become corrupt silently in some way and has stopped accepting new versions of the deck.

为说明起见,我刚刚清理了模拟器并打开了项目,然后将其运行并告诉您我在控制台中看到的内容(带有注释以解释我的所作所为):

To illustrate, I have just cleaned the simulator and opened the project, and I'll run it and tell you what I see in the console (with comments explaining what I did):

81 // launch
65
starting fresh 65
62 // shuffle
59 // shuffle
56 // shuffle
saving 56 // Home button

好的,让我们从Xcode重新启动:

Okay, let's launch again from Xcode:

retrieving 56 // launch
53 // shuffle
50 // shuffle
47 // shuffle
44 // shuffle
saving 44 // Home button

好的,让我们再次从Xcode启动 :

Fine, so let's launch again from Xcode:

retrieving 56 // launch

那是错误!我们已经落后了;我们是从上一个保存中检索套牌,而不是从我们刚才的保存中检索的套牌. (实际上,我可以通过打印出牌组来证明这一点;它具有description属性用于此目的,实际上,我可以看到,它是上一次保存的牌组.)

That's the bug! We've fallen behind; we're retrieving the deck from the previous save, not the one from the save we just did. (I can actually prove this by printing out the deck; it has a description property for just this purpose, and I can actually see that it's the deck from the previous save.)

所以问题是:为什么?我知道如何解决它;保存到文件而不是UserDefaults中.但是我想知道导致此问题的UserDefaults是怎么回事.我怀疑,我要保存到UserDefaults中的对象之一正在引起某种形式的无声破坏,但我不知道怎么回事,因为它们只是数据对象.

So the question is: why? I know how to work around it; save into files instead of UserDefaults. But I'd like to know what's up with UserDefaults here that's causing this problem. I suspect that one of the objects I'm saving into UserDefaults is causing some sort of silent corruption, but I don't see how that can be, as they are just Data objects.

(顺便说一句,调用synchronize并不会改变任何东西,尽管在形式上尚未正式,但根据标头已弃用了它.)

(By the way, calling synchronize changes nothing, and in any case it is deprecated according to the header, even though not yet formally so.)

推荐答案

我将建议整个项目是一个红鲱鱼,问题在于您的测试过程.

I'm going to suggest this entire project is a red herring and that the problem is your testing procedure.

我认为 UserDefaults的保存速度很慢:对UserDefaults的更改要花很长时间才能接受",甚至在出现以下所有信号后 已经发生(synchronize已返回,didChange通知已到达,依此类推).

I theorize that UserDefaults saves slowly: it just takes a really long time for a change to UserDefaults to "take", even after every signal has occurred that the change has happened (synchronize has returned, the didChange notification has arrived, and so on).

因此,我敢打赌,您只是在按下主页"按钮和再次运行该应用程序之间没有足够的时间.要看到可能是这样,请进行以下更改:不要直接从第3步转到第4步,而是插上第3a步,您慢慢地将其计数为10.现在,该错误不会显现出来.

Thus, I'm betting that you're just not allowing enough time between hitting the Home button and running the app again. To see that this might be so, make the following change: Instead of going directly from Step 3 to Step 4, interpose Step 3a, where you count to 10, slowly. Now the bug doesn't manifest itself.

(也可以说在willResignActiveNotification时间保存是错误的.保存时间是在相关数据更改时!!因此,在测试示例中,我们应该在每次改组结束时保存-交易操作-不在用户点击主页"按钮时显示.)

(One could also argue that saving at willResignActiveNotification time is just wrong. The time to save is when the relevant data changes! Thus, in the test example, we should be saving at the end of every shuffle-and-deal operation — not when the user hits the Home button.)

这篇关于iOS UserDefaults落后于已保存的内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆