Подтвердить что ты не робот

Почему очистка 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 не помогает.

4b9b3361

Ответ 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];

Это проще.