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 –