iOS UserDefaults отстает от сохраненного контента - PullRequest
0 голосов
/ 21 сентября 2018

Эта ситуация слишком сложна, чтобы описывать ее простыми словами, поэтому я создал минимальный демонстрационный проект для загрузки и запуска:

https://github.com/mattneub/DefaultsDemo

Вам понадобитсяXcode 10 для тестирования.Вот как выглядит проект, когда он выполняется:

enter image description here

В коде проекта будет много лишних ошибок, но это потому, чтоЯ включил минимальное количество материала из моего приложения real (карточная игра), чтобы воспроизвести проблему, которую я вижу.Существует колода карт и макет карт, и идея заключается в том, что когда пользователь нажимает кнопку «Домой», мы получаем уведомление о том, что приложение подаст в отставку, и мы сохраняем колоду и макет карты в UserDefaults.Когда мы перезапускаем, мы получаем колоду и расположение карт, и пользователь может возобновить игру.

Но, как я объясню, это работает неправильно.И на самом деле тестирование , чтобы увидеть явление очень просто:

  1. Запустите проект на симуляторе.

  2. ХитПеремешать кнопку три-пять раз или около того.(Если у вас закончились карты, нажмите кнопку «Новая колода». Но в моем тестировании это обычно не требуется.)

  3. Нажмите кнопку «Домой» на симуляторе.Это заставляет нас сохранять в UserDefaults.Посмотрите на консоль Xcode;он говорит, что у вас есть много карт в колоде, которая была только что сохранена в UserDefaults.Запомните это число!

  4. Вернувшись в Xcode, остановите проект и запустите его снова, начиная снова с шага 1. Когда мы запускаем, вам сообщают, сколько карт в колоде былотолько что получено из UserDefaults.

Продолжайте повторять эти четыре шага.Что происходит со мной, так это то, что примерно через два или три цикла число на шаге 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 ничего не меняет, и в любом случае он устарел согласно заголовку, хотя формально это еще не сделано.)

1 Ответ

0 голосов
/ 21 сентября 2018

Я собираюсь предположить, что весь этот проект - красная сельдь, и проблема заключается в вашей процедуре тестирования .

Я предполагаю, что UserDefaults спасает медленно :просто требуется очень много времени для изменения UserDefaults, чтобы «принять», даже после каждый сигнал произошел, что изменение произошло (synchronize вернулось, пришло уведомление didChange, ии так далее).

Таким образом, я держу пари, что вы просто не отводите достаточно времени между нажатием кнопки «Домой» и повторным запуском приложения.Чтобы увидеть, что это может быть так, сделайте следующее изменение: вместо того, чтобы перейти непосредственно от шага 3 к шагу 4, вставьте шаг 3a, где вы считаете до 10, медленно .Теперь ошибка не проявляется.

(Можно также утверждать, что экономить на willResignActiveNotification времени просто неправильно. Время сохранения - это когда соответствующие данные изменяются! Таким образом, в тестовом примере мыдолжно сохраняться в конце каждой случайной операции, а не когда пользователь нажимает кнопку «Домой».)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...