在创建对象后自动释放对象时出错

Posted

技术标签:

【中文标题】在创建对象后自动释放对象时出错【英文标题】:Errors autoreleasing objects just after their creation 【发布时间】:2011-09-02 10:32:19 【问题描述】:

我开始研究 ios 开发,我对释放没有存储引用的对象有一些疑问。我看了一下“释放没有指针的对象?”这个问题。建议在创建对象后立即将自动释放消息发送到对象,因此我尝试在以下代码中执行相同操作:

int main(int argc, char *argv[])

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    NSURLResponse * response = nil;
    NSError * error = nil;
    NSData * data;

    data = [NSURLConnection
            sendSynchronousRequest: [[NSURLRequest requestWithURL: 
                                        [[NSURL URLWithString: @"http://www.google.it"] 
                                          autorelease] 
                                     ] autorelease]
                 returningResponse: &response
                             error: &error];

    [data writeToFile: @"/tmp/test.html"
           atomically:NO];

    [data release];
    [pool drain];

    return 0;

我还不能尝试在 XCode 中执行程序,但是我在 linux 下编译并且发送到 NSURLRequest 对象的自动释放消息导致分段错误(我认为这不是由消息本身引起的,而是由池引起的尝试释放对象的排水管,由于自动释放消息)。我发送给 NSURLRequest 对象的自动释放消息有什么问题?

我认为,如果像 requestWithUrl 这样的类方法的参考文档说它“创建并返回 URL 请求”,这意味着我有责任在使用完对象后释放它,我错了吗?在进一步讨论其他任何事情之前,我想很好地理解这个内存管理规则。我希望我的问题不会太愚蠢;-)

呃,最后一个问题:我应该释放同步请求返回的错误和数据对象吗?

提前感谢您的帮助!

【问题讨论】:

【参考方案1】:

+requestWithURL:(和其他)方法已经返回自动释放对象,因此您不应再向它们发送一个自动释放对象。

代码中的额外自动释放会导致对象稍后过度释放并导致应用崩溃。

了解是否必须释放对象的经验法则 - 仅当您使用名称中包含“alloc”、“new”、“copy”的方法创建对象时才需要释放。所有标准 API 都遵循此规则,您在开发自己的方法时应遵循此规则。

因此更正的代码将是:

int main(int argc, char *argv[])

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    NSURLResponse * response = nil;
    NSError * error = nil;
    NSData * data;

    data = [NSURLConnection
            sendSynchronousRequest: [NSURLRequest requestWithURL: 
                                            [NSURL URLWithString: @"http://www.google.it"]                                                                                
                 returningResponse: &response
                             error: &error];

    [data writeToFile: @"/tmp/test.html"
           atomically:NO];

    [pool drain];

    return 0;

P.S.由于上述原因,不应释放数据和错误对象。

【讨论】:

我要感谢大家的即时答复!我怀疑它们是被自动释放的,现在一切都清楚多了:如果我分配了一些我需要释放它的东西(或标记它以供以后自动释放),如果我使用像 +requestWithUrl 这样的类方法创建一个实例(不包含 init /copy/new words) 我不应该发布它,除非我出于某种原因保留它。【参考方案2】:

您的代码应如下所示:

int main(int argc, char *argv[])

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    NSURLResponse * response = nil;
    NSError * error = nil;
    NSData * data;

    data = [NSURLConnection
            sendSynchronousRequest: [NSURLRequest requestWithURL:[NSURL URLWithString: @"http://www.google.it"]] returningResponse:&response error: &error];

    [data writeToFile: @"/tmp/test.html"
           atomically:NO];

    [pool drain];

    return 0;

您无需为使用该方法创建的对象调用autorelease。\

您不需要释放dataerror

所有使用下一个符号NSClass *object = [NSClass classSomeMagicWords]; 返回对象的方法都将返回自动释放的对象,如果您不调用retain,则不应释放该对象。

【讨论】:

【参考方案3】:

您应该删除自动释放。在 iOS/Mac OSX 开发中,使用 Apple 提供的 Classes 几乎是这样的规则,即如果您使用不涉及 init 一词的方法创建对象,您将获得一个已经自动释放的对象。

例如:

NSString *blaah = [[NSString alloc] init];

将返回一个您需要稍后释放的对象。

NSURL *googlelink = [NSURL URLWithString: @"http://www.google.it"];

另一方面,它会给你一个自动释放的对象,如果你再次释放它,它会崩溃。

【讨论】:

【参考方案4】:

在 iOS 内存管理中,您只能拥有通过为其分配内存或复制创建的对象(方法以 alloc 开头或名称中包含“copy”)。

如果你拥有它们,你只需要释放/自动释放它们。 requestWithURLURLWithString 等方法返回已自动释放的对象。

查看 Apple 开发者网站上的 this doc 了解更多信息。

【讨论】:

以上是关于在创建对象后自动释放对象时出错的主要内容,如果未能解决你的问题,请参考以下文章

当我创建 DDXMLDocument 的自动释放对象时,我的应用程序崩溃了

我应该在重新分配之前调用分配给保留属性的自动释放对象的释放吗?

使用 NSOperationQueue 在单独的线程上创建自动释放的对象

Java方法内创建对象实例后,啥时候释放内存(引

为啥 NSThread 可以在不创建我自己的 autoreleasepool 的情况下清除自动释放的对象

NSURLRequest 自动释放:崩溃