Почему очистка NSUserDefaults вызывает EXC_CRASH позже при создании UIWebView? - PullRequest
31 голосов
/ 13 марта 2012

Прежде чем начать, я должен сказать вам, что это только происходит в 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 s.

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

Если вам нужна дополнительная информация, просто дайте мне знать! Спасибо.

РЕДАКТИРОВАТЬ: Выполнение [[NSUserDefaults standardUserDefaults] synchronize] после удаления всех NSUserDefaults не помогает.

Ответы [ 4 ]

25 голосов
/ 16 марта 2012

Я также вижу эту проблему, я думаю, вам нужно сначала создать 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]];

Кто-нибудь видел какие-либо проблемы с этим?

3 голосов
/ 13 марта 2012

Звучит так, будто вы удаляете какую-то частную настройку, что, вероятно, является новой ошибкой, либо с NSUserDefaults (вы не должны быть в состоянии удалить его), либо с UIWebView (он должен справиться с отсутствующей записью).

Вы пробовали метод из другого ответа (установка пустого словаря?).Это дает те же результаты?

Как насчет того, чтобы получить словарное представление NSUserDefaults, получить все ключи и перебрать их, удалив объекты?(дайте мне знать, если вам нужен пример кода для этого).

0 голосов
/ 18 сентября 2013

Проще будет использовать код ниже:

[self saveValue:@"" forKey:@"WebKitLocalStorageDatabasePathPreferenceKey"];
[[NSUserDefaults standardUserDefaults] synchronize];

Это проще.

0 голосов
/ 12 декабря 2012

у меня работает

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];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...