2011-07-06 9 views
9

En mi aplicación escribo múltiples cadenas a la base de datos por defecto, así:¿Por qué NSUserDefaults devuelve una cadena desasignada? (Actualización # 2)

[[NSUserDefaults standardUserDefaults] setObject:@"Hi" forKey:@"GREETING"]; 

Cuando llamo varias veces durante mi tiempo de vida de aplicaciones esto, entonces terminan con un error en el consola después de pasar por encima de este código:

NSString *val = [[NSUserDefaults standardUserDefaults] objectForKey:@"someKey"]; 

aquí con más detalle: crash

Como se puede ver que tengo un punto de interrupción exactamente en la línea con la llamada al método a -stringForKey: de NSUserDefaults. ¡Después de pasar, el choque ya ocurre! No hay posibilidad de siquiera leer lo que está en val. ¡Está desasignado!

Esto sucede con CUALQUIER cadena que puse en NSUserDefaults, desde CUALQUIER LUGAR, y no estoy haciendo nada incorrecto con la administración de memoria. Leaks Instrument es perfecto, al igual que los resultados del Clang Static Analyzer. error

Console:

*** -[CFString retain]: message sent to deallocated instance 0x610ba10 

Top de seguimiento de la pila en depurador después de accidente: (línea superior lee reenvío de)

stacktrace

símbolos de código de Máquina:

arm code

Ahora la parte REALMENTE extraña: tengo un controlador de vista que carga una interfaz de usuario pesada. Cuando destruyo esta vista y la cargo, y la destruyo nuevamente y la vuelvo a cargar, THEN NSUserDefaults está muerto. Bloquear tan pronto como quiera leer una cadena de NSUserDefaults. Es absolutamente siempre el mismo comportamiento.

Pensé que tal vez haya una pérdida de memoria que devora toda la memoria RAM. Pero esto sucede tanto en una gran máquina de desarrollo como en el iPad. Libere y vuelva a cargar la vista dos veces y NSUserDefault tenga este defecto.

Sólo para asegurarse de que no es mi culpa, yo re-escribí mis NSUserDefaults escribir código para algo como esto:

[[NSUserDefaults standardUserDefaults] setObject:[theString copy] forKey:key]; 

Pero aún así, termino con la obtención de las instancias de cadenas desasignado de NSUserDefaults! ¡En el simulador y en el dispositivo! Además, algunas de esas cadenas que intento acceder a haber sido escritos por defecto al inicializar la aplicación en + (void)initialize

NSDictionary *preSettings = [[NSDictionary alloc] initWithObjectsAndKeys: 
@"Hollywood", @"defaultCity", 
nil]; 
[[NSUserDefaults standardUserDefaults] registerDefaults:preSettings]; 

Así que incluso si no cambio esta cadena para la tecla @ "defaultCity y quiero acceder a ella después de un tiempo (cuando volví a cargar esa vista grasa dos veces), termino obteniendo una instancia desasignada de NSUserDefaults.

También traté de reiniciar todo, llamando manualmente a mi método en el delegado de la aplicación que registra ese diccionario predeterminado con NSUserDefaults. No ayuda nada.

He hecho 100% seguro de que th No hay fugas de memoria (probadas en exceso con el instrumento Leaks). No entiendo por qué sucede esto.También intenté retener esas cadenas 5 veces antes de escribirlas en NSUserDefaults (lo que de todos modos sería estúpido), sin éxito.

Ideas?


¡PROBLEMA SOLUCIONADO!

Una de las cadenas devuelta por NSUserDefaults se asignó a una propiedad de retención. Me olvidé de agregar un self. delante de self.theProperty = theStringFromNSUserDefaults que dio como resultado la liberación excesiva de esa cadena en -dealloc cuando la vista fue desasignada.

Aunque es extraño, que pude cargar, destruir, cargar y destruir esa vista. Y luego sucedió en el primer intento de leer cualquier cadena de NSUserDefaults. Es como una cadena desasignada que se propaga a través del diccionario predeterminado o de la base de datos predeterminada y lo desglosa todo, lo que conduce a los algoritmos NSUserDefaults y NSDictionary notally nuts.

Después de corregir ese error único todo funcionó bien. Incluye acceso a todas las demás cadenas en NSUserDefaults también. Funciona, pero sigue siendo un misterio cómo este único olvidado self. tuvo un impacto tan grande.

Gracias a todos los que ayudaron a resolver este problema. Me salvaste de un ataque al corazón. Estaba tan cerca de eso. Bueno, debo comprar algo nuevo ahora ... mi oficina se parece a la habitación de Star Gate después de un ataque Goa'uld.

+0

Se puede publicar su código para guardar la cadena en NSUserDefaults? – iMOBDEV

+0

Sí, verifique mi respuesta actualizada. – openfrog

Respuesta

10

La única forma en que NSUserDefaults podría devolver una cadena desasignada es si sobreescribió una cadena que, en primer lugar, estaba en la memoria caché predeterminada del usuario. Es decir. Me apuesto a que si haces algo como:

p = [NSAutoreleasePool new]; 
NSString *val = [[NSUserDefaults standardUserDefaults] objectForKey:@"someKey"]; 
[val release]; 
[p drain]; 
val = [[NSUserDefaults standardUserDefaults] objectForKey:@"someKey"]; 

Terminarías con una cadena de referencia desasignado en val. ¿Qué estás haciendo con val en todo tu código?


O, como dijo Chuck, esto podría ser un problema de puntero colgando también. Es decir. tiene un puntero colgante que le indica que apunta al objeto en los valores predeterminados del usuario y se libera.


[[NSUserDefaults standardUserDefaults] setObject:[theString copy] forKey:key]; 

Usted esta filtrando la copia de theString en dicho código.

I've made 100% sure that there are no memory leaks (tested excessively with the Leaks instrument). I don't get it why this happens. I also tried to retain those strings 5 times before I write them to NSUserDefaults (which would be stupid anyways), with no success.

El instrumento de fugas no es 100% exacto, ni puede detectar todas las fugas. Si hay una referencia a un objeto en cualquier parte, no se cuenta como una fuga.

I thought maybe there is a memory leak that eats up all the RAM. But this happens on a big development machine as well as on the iPad. Release and reload the view two times and NSUserDefault has this defect.

la teoría de la tirada es más probable correcta; lo más probable es que tenga algo como:

id foo = ... algún objeto ... [foo release]; ... hacer algo con NSUserDefaults de modo que resulte asignar un objeto donde el foo ahora colgante apunta a ... [foo release]; .... oops; ahora el objeto en los valores predeterminados del usuario ha sido desasignado

Fácil de descifrar; active "Registro de pila Malloc" en la pestaña Diagnóstico del panel de ejecución en Xcode. Luego, cuando ocurra el bloqueo, se arrojarán info malloc <address of bad thing> y todos los eventos malloc/free que ocurrieron en esa dirección. Lo más probable es que usted verá algo como:

- malloc 
- free 
.... repeated some # of times .... 
- malloc of some object that you create 
- free of same 
- malloc of a string by NSUserDefaults 
- [inadvertent] free of same 
+2

La cadena NSUserDefaults también podría ser sobreexigida por un puntero colgando. Si un objeto liberado automáticamente se está asignando a un lugar que se supone que debe conservarse, y la cadena NSUserDefaults se está asignando en su lugar, cuando el "propietario" del objeto desasignado intente liberarlo, se liberará esta cadena en su lugar. – Chuck

+0

Por favor revisa mi pregunta actualizada. Trabajo mucho con cadenas autorreleasadas, pero no tiene mucho sentido que esto suceda con TODAS las cadenas que puse en NSUserDefaults y solo después de liberar y volver a cargar mi vista dos veces. – openfrog

+0

Además, otra cosa que probé fue retener las cadenas explícitamente antes de agregar a NSUserDefaults. No ayudó nada. – openfrog

0

¿Dónde intentas retener la cuerda? NSUserDefaults devuelve un autoeditado NSString. ¿Es posible que no hagas nada con eso hasta que el Grupo de Autorelease lo haya limpiado?

+0

No, he leído val de NSUserDefaults y ya devuelve una instancia desasignada. Ese es el problema. El NSLog está siguiendo directamente en la siguiente línea. La cadena devuelta es desasignada. – openfrog

+1

@openfrog - La línea NSLog no prueba que el objeto devuelto está desasignado, solo prueba que ocupa la misma dirección. La memoria podría haber sido reutilizada para otro objeto. – highlycaffeinated

+0

En serio, se desasigna inmediatamente después de recibirlo de objectForKey :! Ni siquiera puedo inspeccionar el valor de val con un punto de interrupción. Después de llamar a objectForKey, el bloqueo ya se produce en el segundo en el que el depurador desea leer el valor devuelto directamente desde esa llamada al método. – openfrog

2

Si su aplicación necesita mantener una referencia a val más allá del alcance del método actual, también necesita retain. Si no lo haces, es posible que se libere automáticamente antes de intentar acceder a él.

+0

No, he leído val de NSUserDefaults y ya devuelve una instancia desasignada. Ese es el problema. – openfrog

+0

@openfrog ¿La línea de código que genera el mensaje de la consola sigue inmediatamente a la llamada 'objectForKey:'? Me sorprendería mucho si ya estuviera desasignado, en lugar de desasignarlo entre que usted obtenga la referencia y usted intente usar la referencia. – highlycaffeinated

+0

En serio, se desasigna inmediatamente después de recibirlo de objectForKey :! Ni siquiera puedo inspeccionar el valor de val con un punto de interrupción. Después de llamar a objectForKey, el bloqueo ya se produce en el segundo en que el depurador desea leer el valor devuelto. – openfrog

Cuestiones relacionadas