In my app I write multiple strings to the defaults database, like this:
[[NSUserDefaults standardUserDefaults] setObject:@"Hi" forKey:@"GREETING"];
When I call multiple times during my app life time this, then I end up with an error in the console after stepping over this code:
NSString *val = [[NSUserDefaults standardUserDefaults] objectForKey:@"someKey"];
Here in more detail:
Like you can see I have a breakpoint exactly on the line with the method call to -stringForKey:
of NSUserDefaults
. After stepping over, the crash happens already! No chance to even read what is in val
. It is deallocated!
This happens with ANY string I put in NSUserDefaults, from ANYWHERE, and I am not doing anything wrong with memory management. Leaks Instrument is all perfect, same as the Clang Static Analyzer results.
Console error:
*** -[CFString retain]: message sent to deallocated instance 0x610ba10
Top of stack trace in debugger after crash: (top line reads forwarding)
Machine code symbols:
Now the REALLY strange part: I have a view controller which loads a heavy UI. When I destroy this view and load it, and destroy it again and load it again, THEN NSUserDefaults is dead. Crash as soon as I want to read a string from NSUserDefaults. It's absolutely always the exact same behavior.
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.
Just to make sure it is not my fault, I re-wrote my NSUserDefaults writing code to something like this:
[[NSUserDefaults standardUserDefaults] setObject:[theString copy] forKey:key];
But still, I end up with getting deallocated string instances from NSUserDefaults! On the simulator and on the device! Also, some of those strings I try to access have been written as default when initializing the application in + (void)initialize
NSDictionary *preSettings = [[NSDictionary alloc] initWithObjectsAndKeys:
@"Hollywood", @"defaultCity",
nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:preSettings];
So even if I do not change this string for the key @"defaultCity and I want to access it after a while (when I reloaded that fat view twice), I end up getting a deallocated instance from NSUserDefaults.
I also tried to re-initialize the whole thing, manually calling my method in the App Delegate which registers that default dictionary with NSUserDefaults. Helps nothing.
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.
Ideas?
PROBLEM SOLVED!
One of the strings returned by NSUserDefaults was assigned to a retaining property. I forgot to add a self.
in front of self.theProperty = theStringFromNSUserDefaults
which resulted in over-releasing that string in -dealloc when the view got deallocated.
Strange though, that I was able to load, destroy, load, destroy that view. And then it happened upon the first attempt of reading any string from NSUserDefaults. It's like a deallocated string propagates through the defaults dictionary or defaults database and tears everything down, driving the NSUserDefaults and NSDictionary algorithms notally nuts.
After correcting that single error everything worked fine. Including access to all other strings in NSUserDefaults as well. Works, but still a mystery how this one single forgotten self.
had such a big impact.
Thank you everyone who helped solving this issue. You saved me from a heart attack. I was so close to it. Well, must buy some new stuff now... my office looks like the Star Gate room after a Goa'uld attack.