简体   繁体   English

为什么 NSUserDefaults 返回一个已释放的字符串? (更新#2)

[英]Why does NSUserDefaults return a deallocated string? (update #2)

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 .就像你可以看到我在 NSUserDefaults 的NSUserDefaults -stringForKey:方法调用的行上有一个断点。 After stepping over, the crash happens already!跨过之后,崩溃已经发生了! No chance to even read what is in val .甚至没有机会阅读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.这发生在我从任何地方放入 NSUserDefaults 的任何字符串中,并且我在 memory 管理方面没有做错任何事情。 Leaks Instrument is all perfect, same as the Clang Static Analyzer results.泄漏仪器非常完美,与 Clang Static 分析仪结果相同。

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.现在真正奇怪的部分:我有一个视图 controller 加载一个沉重的 UI。 When I destroy this view and load it, and destroy it again and load it again, THEN NSUserDefaults is dead.当我销毁这个视图并加载它,然后再次销毁它并再次加载它时,那么 NSUserDefaults 就死了。 Crash as soon as I want to read a string from NSUserDefaults.一旦我想从 NSUserDefaults 读取字符串,就会崩溃。 It's absolutely always the exact same behavior.这绝对是完全相同的行为。

I thought maybe there is a memory leak that eats up all the RAM.我想也许有一个 memory 泄漏会耗尽所有 RAM。 But this happens on a big development machine as well as on the iPad.但这发生在大型开发机器以及 iPad 上。 Release and reload the view two times and NSUserDefault has this defect.两次释放并重新加载视图,NSUserDefault 就有这个缺陷。

Just to make sure it is not my fault, I re-wrote my NSUserDefaults writing code to something like this:只是为了确保这不是我的错,我重写了我的 NSUserDefaults 编写代码,如下所示:

[[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!但是,我最终还是从 NSUserDefaults、模拟器和设备上获得了释放的字符串实例! Also, some of those strings I try to access have been written as default when initializing the application in + (void)initialize此外,在+ (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.因此,即使我不更改键 @"defaultCity 的此字符串并且我想在一段时间后访问它(当我重新加载该胖视图两次时),我最终还是会从 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.我还尝试重新初始化整个事情,在 App Delegate 中手动调用我的方法,该方法将默认字典注册到 NSUserDefaults。 Helps nothing.无济于事。

I've made 100% sure that there are no memory leaks (tested excessively with the Leaks instrument).我已经 100% 确定没有 memory 泄漏(使用泄漏仪器进行了过度测试)。 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.在将它们写入 NSUserDefaults 之前,我还尝试保留这些字符串 5 次(无论如何这都是愚蠢的),但没有成功。

Ideas?想法?


PROBLEM SOLVED!问题解决了!

One of the strings returned by NSUserDefaults was assigned to a retaining property. NSUserDefaults 返回的字符串之一被分配给保留属性。 I forgot to add a self.我忘了添加一个self. in front of self.theProperty = theStringFromNSUserDefaults which resulted in over-releasing that string in -dealloc when the view got deallocated.self.theProperty = theStringFromNSUserDefaults前面,这导致视图被释放时过度释放 -dealloc 中的字符串。

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.然后它发生在第一次尝试从 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.这就像一个解除分配的字符串通过默认字典或默认数据库传播并撕毁所有内容,驱动 NSUserDefaults 和 NSDictionary 算法非常疯狂。

After correcting that single error everything worked fine.更正那个单一错误后,一切正常。 Including access to all other strings in NSUserDefaults as well.包括访问 NSUserDefaults 中的所有其他字符串。 Works, but still a mystery how this one single forgotten self.有效,但仍然是一个谜,这是一个被遗忘的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.好吧,现在必须买些新东西……我的办公室看起来像戈乌德袭击后的星门房间。

The only way that NSUserDefaults could return a deallocated string is if you over-released a string that happened to be in the user defaults cache in the first place. NSUserDefaults可以返回已释放字符串的唯一方法是,如果您过度释放了一个恰好位于用户默认缓存中的字符串。 Ie I'd bet if you do something like:即我敢打赌,如果你这样做:

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

You'd end up with a deallocated string reference in val.你最终会在 val 中得到一个释放的字符串引用。 What are you doing with val throughout your code?您在整个代码中使用val做什么?


Or, as Chuck said, this could be a dangling pointer issue, too.或者,正如 Chuck 所说,这也可能是一个悬空指针问题。 Ie you have a dangling pointer that happens to then point to the object in the user defaults and it gets released.即你有一个悬空指针,它恰好指向用户默认值中的 object 并被释放。


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

You are leaking the copy of theString in that code.您正在该代码中泄漏theString的副本。

I've made 100% sure that there are no memory leaks (tested excessively with the Leaks instrument).我已经 100% 确定没有 memory 泄漏(使用泄漏仪器进行了过度测试)。 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.在将它们写入 NSUserDefaults 之前,我还尝试保留这些字符串 5 次(无论如何这都是愚蠢的),但没有成功。

The leaks instrument is neither 100% accurate, nor can it detect all leaks.泄漏仪器既不能 100% 准确,也不能检测所有泄漏。 If there is a reference to an object anywhere , it isn't counted as a leak.如果在任何地方都引用了 object,则不计为泄漏。

I thought maybe there is a memory leak that eats up all the RAM.我想也许有一个 memory 泄漏会耗尽所有 RAM。 But this happens on a big development machine as well as on the iPad.但这发生在大型开发机器以及 iPad 上。 Release and reload the view two times and NSUserDefault has this defect.两次释放并重新加载视图,NSUserDefault 就有这个缺陷。

Chuck's theory is most likely correct; Chuck 的理论很可能是正确的。 most likely, you have something like:最有可能的是,你有类似的东西:

id foo =... some object... [foo release]; id foo =... 一些 object... [foo release]; ... do something with NSUserDefaults such that it happens to allocate an object where the now-dangling foo points to... [foo release]; ...对 NSUserDefaults 做一些事情,这样它恰好分配了一个 object 现在悬空的 foo 指向... [foo release]; .... oops; ....哎呀; now the object in the user defaults has been deallocated现在用户默认值中的 object 已被解除分配

Easy to figure out;很容易弄清楚; turn on "Malloc Stack Logging" in the Diagnostics tab of the run panel in Xcode.在 Xcode 的运行面板的 Diagnostics 选项卡中打开“Malloc Stack Logging”。 Then, when the crash happens, do info malloc <address of bad thing> and all of the malloc/free events that happened at that address will be spewed.然后,当崩溃发生时,执行info malloc <address of bad thing>并且在该地址发生的所有 malloc/free 事件都将被喷出。 Most likely you'll see something like:您很可能会看到类似的内容:

- 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

If your application needs to maintain a reference to val beyond the scope of the current method, you need to retain it also.如果您的应用程序需要在当前方法的 scope 之外维护对val的引用,您也需要retain它。 If you don't, it may get autoreleased before you try to access it.如果您不这样做,它可能会在您尝试访问它之前自动释放。

Where are you attempting to retain the string?你试图在哪里保留字符串? NSUserDefaults returns an autoreleased NSString . NSUserDefaults返回一个自动释放的NSString Is it possible that you don't do anything with it until the Autorelease Pool has cleaned it up?是否有可能在自动释放池清理它之前你不做任何事情?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM