31 votes

Pourquoi la suppression de NSUserDefaults provoque-t-elle EXC_CRASH plus tard lors de la création d'un UIWebView?

Avant de commencer, je dois vous dire que cela seulement qui se passe dans iOS 5.1. Avant la mise à jour plus récente, ce n'est jamais arrivé et il n'est toujours pas le cas sur toute autre version. Cela dit, voici ce qu'il se passe.

Lorsqu'un utilisateur se déconnecte de mon application, l'une des choses qui arrive, c'est que tous les de la NSUserDefaults d'être supprimés. Plutôt que manuellement en supprimant toutes les clés que je pourrais ajouter à l'utilisateur par défaut, je viens de supprimer complètement tous les de la NSUserDefaults, en utilisant la méthode proposée dans le présent DONC, la question:

NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];

Ce qui semble se produire si, c'est que chaque fois que j'essaie de créer un UIWebView , après avoir éliminé NSUserDefaults, j'obtiens un EXC_CRASH (SIGABRT). Le crash se produit quand je l'appelle [[UIWebView alloc] initWithFrame:frame]. Étrange droite? Complètement arrêter de fumer et la réouverture de l'application permet aux UIWebViews à être créé de nouveau.

Donc, j'ai réussi à comprendre que la suppression d'un défaut serait la cause de la UIWebView problème, mais pour être sûr, j'ai ajouté une symbolique point d'arrêt pour -[NSUserDefaults setObject:forKey:].

-[NSUserDefaults setObject:forKey:] breakpoint

La création d'un UIWebView n'est en effet déclencheur du point d'arrêt.

Piquer à travers le crash logs me donne l'exception de la raison:

-[__NSCFDictionary setObject:forKey:]: attempt to insert nil value (key: WebKitLocalStorageDatabasePathPreferenceKey)

Et voici le début de la trace de la pile:

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

Ce que je fais pour l'instant, et ce qui fonctionne, c'est juste de garder la trace de l' NSUserDefaults clés, j'ai mis de les éliminer manuellement quand j'en ai besoin. Mais il y a toujours un risque que je l'oublie une clé sensible, donc, il suffit d'effacer tous NSUserDefaults me semble plus raisonnable. Donc, je voudrais savoir pourquoi je ne peux pas le faire. Est-ce un bug ou ai-je fait quelque chose de mal?

Si vous voulez plus d'infos, faites le moi savoir! Merci.

EDIT: en Fait [[NSUserDefaults standardUserDefaults] synchronize] après la suppression de tous les NSUserDefaults n'aide pas.

25voto

ppl Points 261

Je vois également ce problème, je pense que vous devez d'abord avoir créé un UIWebView avant d'effacer les valeurs par défaut des utilisateurs pour qu'il se produise. Un projet propre avec ce qui suit entraînera le crash dans iOS5.1, cela fonctionne très bien dans iOS5.0 et versions antérieures:

 UIWebView *webView = [[UIWebView alloc] init];
[webView release];

[[NSUserDefaults standardUserDefaults] setPersistentDomain:[NSDictionary dictionary] forName:[[NSBundle mainBundle] bundleIdentifier]];

UIWebView *anotherWebView = [[UIWebView alloc] init];
[anotherWebView release];
 

Je peux contourner le crash en faisant cela à la place, ce qui évite d'avoir à se souvenir de toutes vos clés de paramètres:

 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]];
 

Quelqu'un voit-il des problèmes à le faire de cette façon?

3voto

jrturton Points 64875

Il semble que vous êtes en train de retirer une sorte de préférence privée, qui est sans doute un nouveau bug, soit avec NSUserDefaults (vous ne devriez pas être en mesure de le retirer) ou UIWebView (il doit composer avec une entrée manquante).

Avez-vous essayé la méthode à partir de l'autre réponse (définition d'un vide dictionnaire?). Ne qui donnent les mêmes résultats?

Que diriez-vous si vous obtenez le dictionnaire de la représentation de NSUserDefaults, obtenir toutes les clés, et itérer sur ceux, enlever les objets? (laissez-moi savoir si vous avez besoin d'un exemple de code pour que).

0voto

Jeeva Points 111

Ça marche pour moi

 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];
 

0voto

Il sera plus simple d'utiliser le code ci-dessous:

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

C'est plus facile.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X