0

これは本当に奇妙なバグです。NSURlConnectionキャンセル原因メモリリーク

私はダウンロードが完了したら、NSURLConnectionとファイルをダウンロードするためのコードを使用しています、私は漏れがありません。 しかし、私がダウンロードをキャンセルすると、1Mメモリーが解放されていません。 私は楽器を使用してテストを行う必要があり、このリークを作成するために特定されMethodeのは

- (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

リークは、変数がその時点でインスタンス化されていることを示しています。そのリークは、リークが実際に開始される場所ではありません。あなたはそれが難しいあなたが精神的に何が起こっているかを追跡するために作ることがあなたのコーディングスタイルの矛盾を持ついくつかの問題があり、この

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

ようなあなたのキャンセル方法でtransientDataを解放する必要があります。あなたが自分の基準に固執するならば、その流れに従うことがより容易でなければなりません。

別のリークが[[NSMutableData alloc] init]呼が+1の保持カウントとNSMutableDataのインスタンスを作成して

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

を発生する可能性ここでは、潜在的にあります。次に、retainでプロパティ(最善)を使用している場合、self.transientData =は保持カウントに別の+1を追加します。これは後で一度だけリリースされるため、NSMutableDataがまだぶら下がっているため、リークが発生します。あなたのコード内でさらに下

あなたはパターン

  1. を使用すると、これがパターンである

  • リリースローカル変数のインスタンスをIVARするインスタンスを割り当てるインスタンスを作成し、ローカル変数へ
  • を割り当てます私が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]; 
    } 
    

    これは、オブジェクトが不要になったときに可能な小型のメモリを搭載したデバイス上で優先されるときについてより明確になるようにautoreleaseを使用していないという利点があります。

    もう少し整理されると恩恵を受けるかもしれない別の不一致は、あなたのイナールをどのように解放するかです。あなたは、交換可能に

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

    は、私はあなたのためのreleaseを呼び出し、あるnilへのポインタを設定しますsynthesizedセッターとしてインスタンス変数のために(つまり、deallocではありません)私のコードでは、後者を使用することになり、あなたのコードでこれを行っていますかなり安全です。

  • +0

    あなたの助けてくれてありがとう、今私はより安全なコードのためにイーグルスを使用できる方法を理解しています。 – Pixman

    2

    self.transientDataはどのように報告されていますか?
    self.transientData = [[NSMutableData alloc] init];で初期化するため、プロパティが値を保持するように設定されている場合は、2回リリースする必要があります。

    この場合、プロパティを設定するには、self.transientData = [[[NSMutableData alloc] init] autorelease];または単に[NSMutableData data];を使用します。
    残りは私にとって大丈夫です。

    +0

    deallocまたはキャンセル機能でself.transientDataがリリースされました... –

    +0

    @Girish Kolari - それは正しいですが、最初の割り当てを正しく行うのではなく、なぜそうするのですか? –

    +0

    リリースまたはself.transientData = nilがない場合は、self.transientDataは解放されません。 deallocで –

    関連する問題