【问题标题】:NSURLConnection leak?NSURLConnection 泄漏?
【发布时间】:2010-11-23 15:48:09
【问题描述】:

我已经设置了一个从 http 获取数据的 nsurl。 当我运行仪器时,它说我有一个泄漏的 NSFNetwork 对象。

以及如何在 (void)ButtonClicked 中释放 theConnection?还是稍后发布?

- (void)ButtonClicked {
    NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:KmlUrl]
                                                cachePolicy:NSURLRequestUseProtocolCachePolicy
                                            timeoutInterval:20.0f];

    NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
    if (theConnection) {
        // receivedData is declared as a method instance elsewhere
        NSMutableData *receivedData = [[NSMutableData data] retain];
        [self setKMLdata:receivedData];
    } else {
        // inform the user that the download could not be made
    }
}


- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    // append the new data to the receivedData
    // receivedData is declared as a method instance elsewhere
    [KMLdata appendData:data];
    NSLog(@"didReceiveData");
}


- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    // release the connection, and the data object
    [connection release];
    [KMLdata release];
}


- (void)connection:(NSURLConnection *)connection  didFailWithError:(NSError *)error
{
    // release the connection, and the data object
    [connection release];
    // receivedData is declared as a method instance elsewhere
    [KMLdata release];

}

【问题讨论】:

    标签: objective-c memory-management memory-leaks nsurlconnection nsurlrequest


    【解决方案1】:

    这是一个常见的问题,可以通过 [object autorelease] 的魔力来解决。在您的代码中,如下所示:

    NSURLConnection *theConnection = [[[NSURLConnection alloc] initWithRequest:theRequest delegate:self] autorelease];
    

    这样,对象被自动添加到“自动释放池”中,并在它不再被引用后在下一个运行循环开始时释放。

    希望有帮助

    编辑:另外,我不明白你为什么需要在你的 receivedData 变量上调用 -retain。

    【讨论】:

    • 虽然调用 autorelease 会起作用,但在释放连接之前释放委托的情况下会失败。更好的方法是将连接分配给实例变量,并在不需要时释放+nil。如果在对象dealloc时仍然分配了连接ivar,则需要在释放连接之前将delegate设置为nil。
    • @rpetrich 我同意你的建议更全面,但很明显他的问题表明了对 iPhone 内存管理的基本误解,因此我想给他一个概念上更简单的解决方案
    • @rpetrich,你能提供一个代码示例吗?我尝试了很多方法来解决这个问题,但仍然存在泄漏。
    • @rpetrich,是的,我也想看看你的例子。
    【解决方案2】:

    我终于找到了答案。

    上述代码中的错误(顺便说一下,这是来自SDK docs 的近乎精确的示例)不在内存管理代码中。自动释放是一种选择,手动释放是另一种选择。无论您如何处理 NSURLConnection 对象,使用 NSURLConnection 都会导致泄漏。

    首先,这是解决方案。只需将这 3 行代码直接复制到 connectionDidFinishLoading、didFailWithError 以及您释放 NSURLConnection 对象的任何其他位置。

    NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil];
    [NSURLCache setSharedURLCache:sharedCache];
    [sharedCache release];
    

    感谢 mpramodjain http://forums.macrumors.com/showthread.php?t=573253 获取代码。

    问题似乎是这样的 - SDK 在 iPhone 上缓存请求和回复。即使您的 NSMutableURLRequest cachePolicy 似乎设置为不从缓存中加载回复。

    愚蠢的是,它似乎默认缓存了很多数据。我正在传输大量数据(分成多个连接)并开始收到内存警告,最后我的应用程序死了。

    我们需要的文档在 NSURLCache(不是 NSURLConnection)中,他们说:

    NSURLCache 实现了缓存 对 URL 加载请求的响应 将 NSURLRequest 对象映射到 NSCachedURLResponse 对象。它是一个 内存和 磁盘缓存。

    提供了一些方法来操作 每个缓存的大小以及 至于控制磁盘上使用的路径 用于缓存数据的持久存储。

    这三行具有完全消除缓存的效果。将它们添加到我的应用程序 (GPS Log) 后,我的#living 对象计数保持稳定。

    【讨论】:

    • 为了记录,我切换到自动释放的 [NSURLConnection connectionWithRequest:request delegate:self] 但我认为这不重要。
    • 如果您的应用发出任何其他应该使用缓存的 NSURLRequest,此解决方案将禁用它们。在这种情况下,更好的解决方案可能是实现缓存的响应委托(具有相同的效果):-(NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse { return nil; }
    • 进一步了解实际发生的情况:NSURLCache 正在缓存对请求的响应,但它使用请求作为键。因此,只要响应被缓存,它就会保留请求。 0 字节缓存解决了这一问题,代价是应用程序发出的所有请求都未缓存;实现委托方法是一种更量身定制的方法。将请求的缓存策略设置为忽略缓存是不够的。
    • 如果您不想完全禁用缓存并且不能或不想使用委托的异步连接,您可以在发送请求后立即调用[[NSURLCache sharedURLCache] removeCachedResponseForRequest:request];
    • 我正在使用 +[NSURLConnection sendAsynchronousRequest:queue:completionHandler:] 和 +[NSURLConnection sendSynchronousRequest:returningResponse:error] 以及设置缓存的方法,但是,活动字节不断增加,最终我的应用程序仅在这些方法上> 30 Mb 后被杀死。你有什么主意吗?对于 sendSynchronousRequest,我在 dispatch_async 中使用 SERIAL_QUEUE。谢谢!
    【解决方案3】:

    你好,你测试过这个委托方法吗?

    - (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
    {
        return nil;
    }
    

    您可以更精确地管理缓存。

    "reset" NSURLCache *sharedCache 会导致代码的其他部分出现问题?

    【讨论】:

      【解决方案4】:

      我正在使用静态方法/自动释放方法,它似乎工作正常:

      [NSURLConnection connectionWithRequest:theRequest delegate:self];
      

      这样您甚至不必担心在委托回调中释放。事实证明,在上面的示例中分配后,连接的保留计数实际上是 2(而不是 1),这改变了我对这种内存“泄漏”的看法。

      @rpetrich 实际上,我认为您不必担心在释放连接之前释放委托。连接保留它的委托,并且连接本身实际上由某种打开的连接队列保留。我在我的博客上写了一篇关于我的 NSURLConnection 实验的博文:

      "Potential leak of object" with NSURLConnection

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-08-13
        • 1970-01-01
        • 1970-01-01
        • 2023-04-08
        • 1970-01-01
        • 2011-09-07
        • 2011-03-21
        相关资源
        最近更新 更多