Эта ситуация слишком сложна, чтобы описывать ее простыми словами, поэтому я создал минимальный демонстрационный проект для загрузки и запуска:
https://github.com/mattneub/DefaultsDemo
Вам понадобитсяXcode 10 для тестирования.Вот как выглядит проект, когда он выполняется:
![enter image description here](https://i.stack.imgur.com/kUaLJ.png)
В коде проекта будет много лишних ошибок, но это потому, чтоЯ включил минимальное количество материала из моего приложения real (карточная игра), чтобы воспроизвести проблему, которую я вижу.Существует колода карт и макет карт, и идея заключается в том, что когда пользователь нажимает кнопку «Домой», мы получаем уведомление о том, что приложение подаст в отставку, и мы сохраняем колоду и макет карты в UserDefaults.Когда мы перезапускаем, мы получаем колоду и расположение карт, и пользователь может возобновить игру.
Но, как я объясню, это работает неправильно.И на самом деле тестирование , чтобы увидеть явление очень просто:
Запустите проект на симуляторе.
ХитПеремешать кнопку три-пять раз или около того.(Если у вас закончились карты, нажмите кнопку «Новая колода». Но в моем тестировании это обычно не требуется.)
Нажмите кнопку «Домой» на симуляторе.Это заставляет нас сохранять в UserDefaults.Посмотрите на консоль Xcode;он говорит, что у вас есть много карт в колоде, которая была только что сохранена в UserDefaults.Запомните это число!
Вернувшись в 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
ничего не меняет, и в любом случае он устарел согласно заголовку, хотя формально это еще не сделано.)