0

这是一个非常奇怪的错误。NSURlConnection取消导致内存泄漏

我使用的代码下载文件与NSURLConnection如果下载完成,我没有泄漏。 但是,如果我取消下载,我有1Mo内存不释放。 我必须做出与仪器测试,并确定了创建这个泄漏梅索德是

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 

真是奇怪

这是我创建,管理并取消下载

代码说明:此下载是核心数据管理对象的一部分,但我认为核心数据不会对我的泄漏负责。

- (void)loadURL:(NSURL *)url 
{ 

    if (currentLoadingDatas) { // just bool for prevent multiple download 

     return; 
    } 
    currentLoadingDatas = YES; 


    NSURLRequest *request = [[NSURLRequest alloc] 
         initWithURL: url 
         cachePolicy:    NSURLRequestReloadIgnoringLocalAndRemoteCacheData 
         timeoutInterval: 60 
         ]; 
    connectionDatas = [[NSURLConnection alloc] initWithRequest:request delegate:self]; 
    [request release]; 

} 

#pragma mark NSURLConnection Delegates 
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 
{ 

    if (!self.transientData) { 

     self.transientData = [[NSMutableData alloc] init]; 
    } 
    [self.transientData setLength:0]; 



} 

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
{ 
    [self.transientData appendData:data]; 


} 



- (void)connectionDidFinishLoading:(NSURLConnection *)connection 
{ 

    [self willChangeValueForKey:@"datas"]; 
[self setValue:self.transientData forKey:@"datas"]; 
    [self didChangeValueForKey:@"datas"]; 

    [self.transientData release]; 


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



} 

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { 


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


} 

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

-(void)cancelDownload 
{ 
    [self.connectionDatas cancel]; 


} 

// fired by coreData 
-(void)willTurnIntoFault 
{ 


    self.transientData = nil; 
    [self cancelDownload]; 

    [super willTurnIntoFault]; 
} 

// fired by coreData 
-(void)didTurnIntoFault 
{ 

    [connectionDatas release]; 

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

    [self.transientData release]; 
    [super didTurnIntoFault]; 
} 

你能帮我找出问题吗?

非常感谢。

回答

1

泄漏表明你的变量是在那个时候实例化的,所以这不是泄漏实际发生的地方。你需要释放transientData在你的取消方法,这样

- (void)cancelDownload 
{ 
    [self.connectionDatas cancel]; 
    self.transientData = nil; 
} 

有与您的编码风格不一致的一些问题,可能使你更难在精神上跟踪到底是怎么回事。如果你坚持自己的标准,应该更容易遵循流程。

这是潜在的其中另一个泄漏可能发生

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 
{ 
    if (!self.transientData) { 
     self.transientData = [[NSMutableData alloc] init]; // leaky line 
    } 
    [self.transientData setLength:0]; 
} 

[[NSMutableData alloc] init]呼叫与+1的保留计数创建的NSMutableData一个实例。然后,如果您使用retain的属性(最好),那么self.transientData =将采用另一个保留,为保留计数添加另一个+1。这是后来只发布一次,因此你有一个泄漏,因为NSMutableData仍然是悬而未决。

在你的代码再往下,您使用模式

  1. 创建实例,并分配给本地变量
  2. 分配实例伊娃
  3. 释放局部变量实例

这是模式当我不在init方法中时,我会使用它。因此之前该方法应被变更为:

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 
{ 
    if (!self.transientData) { 
     NSMutableData *tmpTransientData = [[NSMutableData alloc] init]; 
     self.transientData = tmpTransientData; 
     [tmpTransientData release]; 
    } 
    [self.transientData setLength:0]; 
} 

这具有这样你是更明确的了解,当对象不再需要这是优选的,当有可能在具有小存储装置不使用一个自动释放的益处。

另一个可能有益于整理的不一致是如何释放你的ivars。你还可以互换在代码中做到了这一点

[self.transientData release]; 
self.transientData = nil; 

我会用后者在我的代码(即不dealloc)为实例变量为synthesized setter方法调用release为您和指针设置为nil这是相当安全。

+0

感谢您的帮助,现在我明白我如何使用ivars获得更安全的代码。 – Pixman

2

self.transientData属性是如何声明的?
因为您初始化为:self.transientData = [[NSMutableData alloc] init];,并且如果该属性设置为保留该值,则需要释放它两次。

如果是这样,设置属性使用:self.transientData = [[[NSMutableData alloc] init] autorelease];或简单地[NSMutableData data];
其余的对我来说似乎没问题。

+0

发布self.transientData在dealloc或取消功能应该可以解决您的问题... –

+0

@Girish科拉里 - 没错,但为什么这样做,而不是正确地做第一个分配? – 2011-07-24 16:36:59

+0

如果您没有版本或self.transientData = nil,则self.transientData不会被释放;在dealloc –