Таким образом, после экспериментов и прибегая к помощи выводам я пришел к распределились следующим образом:
значительного изменение обновления и фактически любой процесс, который запускает приложение позади экрана блокировки проблемы здесь. Файл .plist (NSUserDefaults defaultUser) загружает защиту (NSFileProtectionCompleteUntilFirstUserAuthentication), так что он недоступен только после первой разблокировки после запуска приложения. Поэтому, если процесс запускает ваше приложение в фоновом режиме, и ваше приложение пытается получить доступ к умолчанию по умолчанию пользователя пользователя, он не может загрузить файл и поэтому дает вам новый пустой набор пользовательских значений по умолчанию.
Что произошло в моем случае, так это то, что приложение перешло в состояние ожидания, когда EULA и PP будут приняты, поскольку он считывает данные по умолчанию (которые не могут быть прочитаны), что они не были приняты все же. После разблокировки телефона и повторного открытия приложения, которое, пожалуйста, обратите внимание, уже «запущено» - есть некоторые процессы, которые пишут NSUserDefaults, некоторые в моем приложении и некоторые из библиотек, которые использует мое приложение. В большинстве случаев я вызывал синхронизацию по умолчанию, поэтому уничтожал старые значения по умолчанию, которые невозможно было прочитать. Полагаю, это может случиться для многих людей.
Существует несколько различных решений.
Сначала я написал класс, эквивалентный NSUserDefaults, обертывающий NSMutableDictionary и сохраняющий словарь в .plist в библиотеке/поддержке приложений. Я изменил защиту файла на NSFileProtectionNone. Обратите внимание, что это не рекомендуется, если вы храните конфиденциальную информацию в этом файле. Также обратите внимание, что вы должны устанавливать разрешения для файла каждый раз, когда вы его пишете. Что-то вроде:
NSError *error;
BOOL saved = [defaultsDic writeToURL:defaultsFileUrl atomically:YES];
[[NSFileManager defaultManager] setAttributes:[NSDictionary dictionaryWithObject:NSFileProtectionNone forKey:NSFileProtectionKey]ofItemAtPath:[defaultsFileUrl path] error:&error];
Этот метод работает хорошо, но, как выясняется, у меня был еще один вопрос, с данными, которые я читал и писал с брелка. См. Ссылку в моем вопросе выше, ее та же проблема. Значения keychain имеют одинаковую защиту вплоть до первой разблокировки после запуска приложения. Я не хотел удалять защиту из брелка, и на самом деле мне было не очень удобно снимать защиту с моих пользовательских настроек по умолчанию.
Итак, следующее решение - фактически решить проблему. Не пытайтесь получить доступ к защищенным данным, если приложение запущено за экраном блокировки! Это означает, что я должен обнаружить, что приложение запускается за экраном блокировки, а затем дождитесь, пока приложение будет разблокировано, прежде чем я начну читать мои значения по умолчанию и значения привязки для пользователя.
Первое требование - проверить запуск приложения, если доступны защищенные данные, возможно, в applicationDidLaunch или в другом месте.
[[UIApplication sharedApplication]isProtectedDataAvailable]
Если это не так, когда приложение запущено, то вы находитесь за экраном блокировки. Вы должны остановиться на этом этапе и воздерживаться от любых операций, которые обращаются к NSUserDefaults или Keychain (или к любому защищенному файлу, если на то пошло!). Затем вам нужно дождаться сигнала о том, что защищенные данные стали доступными. AppDelegate получает следующее, когда пользователь открывает экран блокировки:
-(void)applicationProtectedDataDidBecomeAvailable:(UIApplication *)application
После того, как вы получите, что вы можете продолжать выполнение приложения.
В моем случае я контролирую все в одном классе. Когда этот класс создаются (который происходит только при запуске приложения) я проверяю, если защищенные данные доступны или нет, и подписаться на NSNotificationCenter для того же уведомление:
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(applicationProtectedDataDidBecomeAvailable) name:UIApplicationProtectedDataDidBecomeAvailable object:nil];
Так с этим вторым способом, проблема решена и данные остаются защищенными, и все довольны.
Есть и другие подобные неотвеченные вопросы о SO. Похоже, может быть, неразрешенная ошибка. Вы можете обойти это, используя NSCoder или Core Data. –