Почему очистка NSUserDefaults вызывает EXC_CRASH позже при создании UIWebView?
Прежде чем начать, я должен сказать вам, что это происходит только в iOS 5.1. Перед самым последним обновлением этого никогда не было, и это все еще не происходит ни на одной другой версии. Тем не менее, вот что происходит.
Когда пользователь выходит из моего приложения, одна из вещей, которая происходит, - это удаление всех NSUserDefaults
. Вместо того, чтобы вручную удалять каждый ключ, который я могу добавить к пользовательским значениям по умолчанию, я просто полностью удалю все NSUserDefaults
, используя метод, предложенный в этот вопрос SO:
NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];
Что-то похожее на то, что каждый раз, когда я пытаюсь создать UIWebView
после удаления NSUserDefaults
, я получаю EXC_CRASH (SIGABRT)
. Сбой происходит, когда я вызываю [[UIWebView alloc] initWithFrame:frame]
. Странно? Полное завершение и повторное открытие приложения позволяет создать UIWebView
снова.
Итак, мне удалось выяснить, что удаление значений по умолчанию вызовет проблему UIWebView
, но, конечно, я добавил символическую точку останова для -[NSUserDefaults setObject:forKey:]
.
![-[NSUserDefaults setObject:forKey:] breakpoint]()
Создание UIWebView
действительно вызывает точку останова.
Пробивание журналов сбоев дает мне исключение:
-[__NSCFDictionary setObject:forKey:]: attempt to insert nil value (key: WebKitLocalStorageDatabasePathPreferenceKey)
И вот начало трассировки стека:
0 CoreFoundation 0x3340688f __exceptionPreprocess + 163
1 libobjc.A.dylib 0x37bd4259 objc_exception_throw + 33
2 CoreFoundation 0x33406789 +[NSException raise:format:] + 1
3 CoreFoundation 0x334067ab +[NSException raise:format:] + 35
4 CoreFoundation 0x3337368b -[__NSCFDictionary setObject:forKey:] + 235
5 WebKit 0x3541e043 -[WebPreferences _setStringValue:forKey:] + 151
6 UIKit 0x32841f8f -[UIWebView _webViewCommonInit:] + 1547
7 UIKit 0x328418d7 -[UIWebView initWithFrame:] + 75
8 MyApp 0x0007576f + 0
9 UIKit 0x326d4dbf -[UIViewController view] + 51
10 UIKit 0x327347e5 -[UITabBarController transitionFromViewController:toViewController:transition:shouldSetSelected:] + 93
11 UIKit 0x32734783 -[UITabBarController transitionFromViewController:toViewController:] + 31
12 UIKit 0x327340bd -[UITabBarController _setSelectedViewController:] + 301
13 UIKit 0x327bd5d9 -[UITabBarController _tabBarItemClicked:] + 345
Что я делаю сейчас, и что работает, просто отслеживает ключи NSUserDefaults
, которые я установил, и удаляя их вручную вручную, когда это необходимо. Но всегда есть риск, что я могу забыть чувствительный ключ, поэтому просто очистка всех NSUserDefaults
поражает меня как более разумную. Итак, я хотел бы знать, почему я не могу этого сделать. Это ошибка, или я делаю что-то неправильно?
Если вам нужна дополнительная информация, просто дайте мне знать! Спасибо.
EDIT: Выполнение [[NSUserDefaults standardUserDefaults] synchronize]
после удаления всех NSUserDefaults
не помогает.
Ответы
Ответ 1
Я тоже вижу эту проблему, я думаю, вы должны сначала создать UIWebView, прежде чем очищать пользовательские значения по умолчанию. Чистый проект со следующим вызовом приведет к сбою в iOS5.1, это отлично работает в iOS5.0 и ранее:
UIWebView *webView = [[UIWebView alloc] init];
[webView release];
[[NSUserDefaults standardUserDefaults] setPersistentDomain:[NSDictionary dictionary] forName:[[NSBundle mainBundle] bundleIdentifier]];
UIWebView *anotherWebView = [[UIWebView alloc] init];
[anotherWebView release];
Я могу обойти крушение, сделав это вместо этого, чтобы избежать необходимости запоминать все ваши настройки:
id workaround51Crash = [[NSUserDefaults standardUserDefaults] objectForKey:@"WebKitLocalStorageDatabasePathPreferenceKey"];
NSDictionary *emptySettings = (workaround51Crash != nil)
? [NSDictionary dictionaryWithObject:workaround51Crash forKey:@"WebKitLocalStorageDatabasePathPreferenceKey"]
: [NSDictionary dictionary];
[[NSUserDefaults standardUserDefaults] setPersistentDomain:emptySettings forName:[[NSBundle mainBundle] bundleIdentifier]];
Кто-нибудь видит какие-либо проблемы с этим?
Ответ 2
Похоже, что вы удаляете какие-то частные предпочтения, что, вероятно, является новой ошибкой, либо с NSUserDefaults (вы не должны ее удалять), либо UIWebView (он должен справиться с отсутствующей записью).
Вы пробовали метод из другого ответа (установка пустого словаря?). Это дает те же результаты?
Как получить представление словаря NSUserDefaults, получить все ключи и перебрать их, удалить объекты? (дайте мне знать, если вам нужен образец кода для этого).
Ответ 3
Это работает для меня
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSDictionary *userDefaultsDictionary = [userDefaults dictionaryRepresentation];
NSString *strWebDatabaseDirectory = [userDefaultsDictionary objectForKey:@"WebDatabaseDirectory"];
NSString *strWebKitLocalStorageDatabasePathPreferenceKey = [userDefaultsDictionary objectForKey:@"WebKitLocalStorageDatabasePathPreferenceKey"];
[userDefaults removePersistentDomainForName:[[NSBundle mainBundle] bundleIdentifier]];
if (strWebDatabaseDirectory) {
[userDefaults setObject:strWebDatabaseDirectory forKey:@"WebDatabaseDirectory"];}
if (strWebKitLocalStorageDatabasePathPreferenceKey) {
[userDefaults setObject:strWebKitLocalStorageDatabasePathPreferenceKey forKey:@"WebKitLocalStorageDatabasePathPreferenceKey"];}
[userDefaults synchronize];
Ответ 4
Проще будет использовать следующий код:
[self saveValue:@"" forKey:@"WebKitLocalStorageDatabasePathPreferenceKey"];
[[NSUserDefaults standardUserDefaults] synchronize];
Это проще.