我该如何在iPhone应用程序中可靠地释放内存?

4
如果我有这段代码
 NSString *postData = [@"foo=" stringByAppendingString:fooText.text];
 ...
 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
 ...
 [postData release];   //this causes crash
 [request release];    //this causes crash

现在我明白这是根据苹果文档的预期行为。如果我删除释放代码,崩溃就不会发生,但我发现*request仍然存在内存泄漏问题。所以我重写了代码。
NSString *postData;
//postData = [NSString alloc];  // this line commented out since OP
postData = [@"foo=" stringByAppendingString:fooText.text];
...
NSMutableURLRequest *request;
request = [NSMutableURLRequest alloc];
request = [request initWithURL:url];
    ...
    [postData release];   //this still crashes #
    [request release];    //this works fine

我不太明白为什么会在#处崩溃。这里有什么推荐的最佳实践吗?我认为我可能漏掉了一些东西,因为我经常看到“简写”方法(顶部)有一个释放(例如Kochan的Objective-C编程),但Apple文档说这是错误的。

4个回答

7
一般来说,如果您调用的是帮助程序静态方法(例如stringByAppendingString),则不应该释放它。该字符串在被提供给您之前已添加到自动释放池中。如果您调用alloc然后是init...方法,则需要释放该对象。
您的代码中还有其他需要注意的事项:
  • 在第二个示例中,您分配了postData,然后立即用由stringByAppendingString创建的另一个字符串替换它,这会导致内存泄漏。
  • 您的释放调用有误,应该是[postData release][request release]
  • 我在您的示例中没有看到postDatarequest之间的任何关联,因此不确定您具体想表达什么。

1
“一般的经验法则是,如果你正在调用一个帮助器静态方法(例如stringByAppendingString),那么你不应该释放它。” 这正是我在寻找的!然而,在第一个示例中,如何释放request,因为instruments指示存在内存泄漏(这都是在一个简单的方法内)。这似乎表明autorelease对request无效。 - Gazzer
在第一个例子中,您自己分配和初始化了请求,因此您应该释放它。当您这样做时,您会遇到什么崩溃?EXC_BAD_ACCESS?这通常意味着您(或者您给请求的某些东西)已经释放了请求,而您没有意识到。 - Matt Greer

1

首先,在您的第二个示例中,行postData = [NSString alloc];是完全不必要的 - postData会被下一行覆盖。其次,回答您为什么会崩溃的问题 - 没有好的答案 - 系统可以选择在保留计数达到0后随时释放内存。为了更轻松地调试问题,您应该打开NSZombieEnabled,它将立即涂鸦任何已释放的对象,为您提供100%可靠的测试崩溃的方法。

此外,分配/初始化在单独的行上是不好的风格。

总的来说,您应该专注于遵循内存指南。如果您没有遵循指南,则行为可能未定义。


0
为您的对象分配内存并初始化最好在一行完成 - init方法可能返回不同的对象,同时它可以帮助避免您在第二个示例中犯的错误。
NSString *postData; // Define pointer to string
postData = [NSString alloc]; // Allocating nsstring pointer and assign it to variable
postData = [@"foo=" stringByAppendingString:fooText.text]; // assign to postData new **autoreleased** string object. result of the previous assignment is abandoned.
[postData release];  //so here you release autoreleased object!!

我无法弄清楚为什么在第一个例子中 [equest release]; 会导致崩溃。

P.S. 我还没有完全清醒,或者应该是 [postData release] 而不是 [release postData]


-1
NSString *postData;
postData = [[NSString alloc]init];
postData = [@"foo=" stringByAppendingString:fooText.text];
...
NSMutableURLRequest *request;
request = [[NSMutableURLRequest alloc]initWithURL:url];
...
    [postData release];   
    [request release]; 

试试这个。


你的示例仍然存在与原始问题相同的postdata问题。 - Vladimir
最好在你完成使用变量后立即添加 [postData release];。你必须在使用后释放内存。 - Nithin
1
postData 在第三行赋值后包含一个自动释放的对象 - 你不能释放它。而在第二行分配的字符串只是泄漏了,因为你简单地覆盖了它。 - Vladimir
NSString *postData = [[NSString alloc]init]; postData = @"foo=%@",[fooText.text]; 这也可能被使用,注意这可能不是你的问题原因。 - Nithin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接