¿Por qué la limpieza de NSUserDefaults causa EXC_CRASH más tarde al crear una UIWebView?

Antes de comenzar, debería decirte que esto solo sucede en iOS 5.1. Antes de la actualización más reciente, esto nunca había sucedido y todavía no sucede en ninguna otra versión. Dicho esto, esto es lo que está sucediendo.

Cuando un usuario cierra session en mi aplicación, una de las cosas que sucede es que todos los NSUserDefaults se borran. En lugar de eliminar manualmente todas las keys que podría agregar a los valores pnetworkingeterminados del usuario, simplemente NSUserDefaults completo todos los NSUserDefaults , utilizando el método sugerido en esta pregunta SO :

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

Sin embargo, lo que parece ocurrir es que cada vez que bash crear un UIWebView después de haber eliminado NSUserDefaults , obtengo un EXC_CRASH (SIGABRT) . El locking ocurre cuando [[UIWebView alloc] initWithFrame:frame] . ¿Extraño, cierto? UIWebView fumar y volver a abrir completamente la aplicación permite que UIWebView s se cree de nuevo.

Entonces, me las arreglé para descubrir que eliminar los valores pnetworkingeterminados causaría el problema de UIWebView , pero para asegurarse, agregué un punto de corte simbólico para -[NSUserDefaults setObject:forKey:] .

- [NSUserDefaults setObject: forKey:] punto de interrupción

La creación de un UIWebView hecho desencadena el punto de interrupción.

Revisar los loggings de lockings me da la razón de exception:

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

Y aquí está el comienzo de la traza de stack:

 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 

Lo que estoy haciendo por ahora, y lo que funciona, es simplemente realizar un seguimiento de las keys NSUserDefaults que he configurado y eliminarlas todas manualmente cuando lo necesito. Pero siempre existe el riesgo de olvidar una key sensible, por lo que simplemente borrar todos los NSUserDefaults me parece más sensato. Entonces, me gustaría saber por qué no puedo hacer eso. ¿Es un error o estoy haciendo algo mal?

Si quieres más información, ¡simplemente avísame! Gracias.

EDIT: Hacer [[NSUserDefaults standardUserDefaults] synchronize] después de eliminar todos NSUserDefaults no ayuda.

Estoy viendo este problema también, creo que primero debes haber creado un UIWebView antes de borrar los valores pnetworkingeterminados del usuario para que se produzca. Un proyecto limpio con lo siguiente provocará el locking en iOS5.1, esto funciona bien en iOS5.0 y versiones anteriores:

 UIWebView *webView = [[UIWebView alloc] init]; [webView release]; [[NSUserDefaults standardUserDefaults] setPersistentDomain:[NSDictionary dictionary] forName:[[NSBundle mainBundle] bundleIdentifier]]; UIWebView *anotherWebView = [[UIWebView alloc] init]; [anotherWebView release]; 

Puedo evitar el crash haciendo esto, lo que evita tener que recordar todas las keys de configuration:

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

¿Alguien ve algún problema con hacerlo de esta manera?

Parece que está eliminando algún tipo de preference privada, que probablemente sea un nuevo error, ya sea con NSUserDefaults (no debería ser capaz de eliminarlo) o UIWebView (debe hacer frente a una input que falta).

¿Has probado el método de la otra respuesta (configurando un dictionary en blanco?). ¿Eso da los mismos resultados?

¿Qué tal si obtienes la representación de dictionary de NSUserDefaults, obtienes todas las keys e iterás a través de ellas, eliminando los objects? (Avíseme si necesita un ejemplo de código para eso).

Esto funciona para mi

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

Más simple será usar el código a continuación:

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

Es más fácil.