4

ここにトリッキーな質問がありますが、その答えは、私を含む多くのネットワーキングの見習いにとって役立つかもしれません。

コンテキストに関する背景情報:

  • オンライン サービスからデータをダウンロードするとします。
  • これを非同期で行いたい
  • 一度に 1 つのダウンロードを行いたい場合は、前のダウンロードが完了してから別のダウンロードを行うことができます。

これを行う 1 つの優れた方法は、再帰を使用することです。あなたが思いつくことができる一般的な実装の問題は、ネットワーク完了ブロックと自己の間の保持サイクルです。これは、weakSelf 参照ポインターを使用して解決できます。

しかし、再帰呼び出しの保持サイクルはどうですか?

次のように、ダウンロード管理クラスを自己指す再帰スタックを実装しました。

-(void)startNetworkDownloadForObjectAtIndex:(int) anIndex
{
    __typeof__(self) __weak weakSelf = self;
    NSURL *urlForObjectAtIndex = [SomeClass URLforIndex:anIndex];
    [self.downloadManager getResourceAtURL:urlForObjectAtIndex success:^(AFHTTPRequestOperation *operation, id responseObject) {
                               if (indexOfObjectToDownload < weakself.totalNumberOfObjectsToDownload) [weakSelf startNetworkDownloadForObjectAtIndex:indexOfObjectToDownload+1];
                               else [weakSelf startDOwnloadTimer]; 
                            }
                            failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                                // response code is in operation.response.statusCode
                                [weakSelf handleNetworkError:error];
                            }];
}


-(void)handleNetworkError:error
{
     // Do some error handling
     [self startNetworkDownloadForObjectAtIndex:self.lastUnsentObjectIndex];
 }

-(void)startDownloadTimer
{
     if (self.syncEngineTimer) [self.syncEngineTimer invalidate];
     self.syncEngineTimer = [NSTimer scheduledTimerWithTimeInterval:kSyncTimeInterval
                                                        target:self
                                                    selector:@selector(restartNetworkDownload)
                                                      userInfo:nil
                                                       repeats:NO];
}

-(void)restartNetworkDownload
{
      // do some fancy calculations / etc to manage your download
     int anIndex = theResultOfYourCalculation;
     [self startNetworkDownloadForObjectAtIndex:anIndex];
}

わかりました。これは、複数のネットワーク ダウンロード (たとえば、100 枚のちらつき画像を取得する) の再帰呼び出しの可能性のある例であり、たとえば、1 時間後に新しい画像を取得しようとします。コーディングのタイプミスはご容赦ください。

これは、iOS 5.0 以上の iOS デバイス用の ARC で実行しています。

成功と失敗の完了ブロックへの参照を保持する self.downloadManager を使用するときに、weakSelf 参照ポインターを使用することで、保持サイクルの最初のレベルを明らかに破りました。これはすべて問題なく、楽器によく合います。

ここで、Instruments の割り当てを確認すると、複数のダウンロードに対してダウンロード操作を開始します。器具は漏れを示さない。しかし、ヒープを定期的に保存すると、ヒープがゆっくりと成長しているのがわかります。

割り当てを確認し、コール スタックを確認すると、ブロックが startDownloadTimer を使用して自分自身への参照を保持しているように見えます。

考えられる原因と解決策についての説明は大歓迎です:)

4

1 に答える 1

1

タイマーはそのターゲット ( self) を保持します。

この質問の解決策を試してください:保持サイクルを防ぐための NSTimer ターゲットへの弱い参照

またはdispatch_afterタイマーの代わりに使用します。

于 2013-10-02T11:20:01.633 に答える