0

xcode アナライザーを使用すると、オブジェクトの潜在的なリークに関する警告が表示されます。この警告はややこしいので、なぜこのエラーが発生するのか説明が必要です。問題のオブジェクトへのポインターを mediaSources が保持するコードを次に示します。

.h ファイルでは、MediaSources クラスへのポインターが作成され、retain プロパティが与えられます。

@interface RootViewController : UIViewController <...>
{
    ...

    MediaSources                *mediaSources;

    ...
}

@property (nonatomic, retain)   MediaSources            *mediaSources;

.m ファイル (rootViewController) には、何度も呼び出すことができるメソッドがあります。したがって、各エントリでオブジェクトを解放し、新しいオブジェクトを割り当てます。MediaSources オブジェクトはバックグラウンド タスクを実行するため、完了するまで解放したくありません。クラスが割り当てられている行で autoRelease を使用すると、クラッシュします。:

-(void) getSelectedMediaSources
{
    [self setMediaSources: nil];    // release old stuff and nilify 
    [self setMediaSources: [[MediaSources alloc] init]]; 
    [self.mediaSources checkForMediaSourceUpdates];
}

また、.m ファイルでは、mediaSources も合成され、dealloc で解放されます。

@synthesize mediaSources;

...

- (void)dealloc {
    ...
    [mediaSources release];
    ...

    [super dealloc];
}

この警告が表示される理由を説明してください。どうやって漏れがあるのか​​ わかりません。Dealloc は、このオブジェクトの最後のコピーを解放する必要があります。

checkForMediaSourceUpdates からのコードのリクエストに応じて。少しややこしくなりますが、要点は以下の通りです。

(void) checkForMediaSourceUpdates
{    
    NSString *s = [NSString  stringWithFormat:@"http://www.mywebsite.com/mediaSources/%@/mediaSources.plist", countryCode];

    NSURL *url = [NSURL URLWithString:s];
    NSURLRequest *req = [NSURLRequest requestWithURL:url  cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:60.0];
    MyDownloader *d = [[MyDownloader alloc] initWithRequest:req];
    [self.connections addObject:d];
    [[NSNotificationCenter defaultCenter] addObserver:self  selector:@selector(checkForMediaSourceUpdatesDownloadFinished:) name:@"connectionFinished" object:d];
    [d.connection start];
    [d release];
}

-(void) checkForMediaSourceUpdatesDownloadFinished: (NSNotification *) n 
{
    MyDownloader *d = [n object];
    NSData *data = nil;
    if ([n userInfo]) {
        NSLog(@"In checkForMediaSourceUpdatesDownloadFinished: MyDownloader returned an error");
    }
    else {
        data = [d receivedData];

        // do something with the data
    }
}

myDownloader クラスは、入力 NSURLRequest で指定されたファイルのダウンロードを実行します。ダウンロードが完了すると、このクラスは「connectionFinished」という名前の NSNotification を生成します。このクラスのユーザーは、この通知に登録し、このクラスのすべてのクリーンアップ操作を処理する必要があります。ダウンロードが失敗した場合、このクラスは「connectionFinished」という名前の NSNotification を生成しますが、エラーが発生したことを示す userInfo が追加されます。繰り返しになりますが、このクラスのユーザーは、この通知に登録し、このクラスのすべてのクリーンアップ操作を処理する必要があります。

4

3 に答える 3

4

定義ごとに、自動解放されたオブジェクトを合成されたセッターに渡します。セッター自体がオブジェクトを保持するため、次の行は間違っています。

[self setMediaSources: [[MediaSources alloc] init]]; 

そのはず:

[self setMediaSources: [[[MediaSources alloc] init] autorelease]]; 

また、前にセッターを呼び出す必要はありませんnil。セッターを介して別のオブジェクトを設定すると、古いオブジェクトが解放されます。合成されたセッターは次のようになります。

- (void) setMediaSources:(MediaSources *)mediaSources {
  if (_mediaSources != mediaSources) {
    [_mediaSources release];
    _mediaSources = [mediaSources retain];
  }
}

MediaSource問題は、 を呼び出すたびに新しいを割り当てる必要があるのはなぜgetSelectedMediaSourcesですか? autoreleased の割り当てを解除すると、どのようなクラッシュが予想されますMediaSourceか? 別のオブジェクトのデリゲートとして設定していますか、またはに登録していNSNotificationCenterますか? その場合は、デリゲートを無効にするか、通知センターから削除することを忘れないでください。

于 2013-05-21T18:41:07.597 に答える
3

他の回答で既に述べたように、次のautoreleaseように d インスタンスをセッターに渡す必要があります。

[self setMediaSources: [[[MediaSources alloc] init] autorelease]]; 

これを行った結果として発生しているクラッシュは、 でバックグラウンド処理を行っていることが原因のようですcheckForMediaSourceUpdates。このメソッドでバックグラウンド処理を行う場合selfは、バックグラウンド タスクの全期間にわたって有効であることを確認する必要があります。[self retain];最初と最後に手動で呼び出すことは完全に有効です[self release];。(注:ブロック内からオブジェクトを参照している場合、GCDブロックは自動的にオブジェクトを保持/解放します)。self

編集:問題を今知っていることを願っています.mAuがそれを呼び出しました. リクエストが実行されている場合、インスタンスの(RootViewControllerオブジェクトごとの)保持カウントは 1 つだけです。MediaSourcesリクエストが完了する前にメソッドを再度呼び出すと、MediaSourcesオブジェクトが解放されます。そのため、リクエストが終了しNSNotification、コールバック メッセージを送信しようとすると、オブザーバー インスタンスが消失しているため、アプリがクラッシュします。

これを解決するには 2 つの方法があります (ケースに適した方を使用してください)。

  1. の最後にとを追加[self retain];します。checkForMediaSourceUpdates[self release];checkForMediaSourceUpdatesDownloadFinished:
  2. または、 を追加[[NSNotificationCenter defaultCenter] removeObserver: self]-[MediaSources dealloc]ます。

why do you need to allocate a new MediaSource on every call to getSelectedMediaSources?ところで、実行中のリクエストがある可能性があるたびに、なぜ新しいリクエストを開始するのかを考える必要があります。あなたのデザインには何か非常に問題があります。

于 2013-05-21T19:59:48.433 に答える
0
[self setMediaSources: [[MediaSources alloc] init]]; 

新しい MediaSources オブジェクトを 2 回保持しています。1 回はallocで、もう 1 回はsetMediaSourcesです。一度だけ解放します。

試す:

[self setMediaSources: [[[MediaSources alloc] init] autorelease]]; 

コメントからのフォローアップ:

はい、変数を直接設定できますが、根本的な問題は解決しません。余分な保持のために既存のコードが機能し、保持/解放のバランスを取ると失敗するようです。古い mediaSources オブジェクトへの弱い参照を保持しているユーザーを特定し、解放する前にその参照を解除する必要があります。

于 2013-05-21T18:42:27.610 に答える