Ciclo di completamento della networking, ricorsione e ciclo di conservazione ARC

Ecco una domanda complicata, a cui la risposta potrebbe rivelarsi utile per molti apprendisti di networking, incluso me.

Alcune informazioni di base sul context:

  • Diciamo che vuoi scaricare i dati da un servizio online
  • vuoi farlo in modo asincrono
  • vuoi fare un download alla volta, quindi magari ne fai un altro al completamento del precedente.

Un modo pulito per farlo è usare la ricorsione. Il problema con le implementazioni comuni che si possono get è il mantenimento dei loops, tra i blocchi di completamento della networking e il sé. Questo può essere risolto usando i puntatori di riferimento di weakSelf.

Ma, per quanto riguarda i loops di conservazione per le chiamate ricorsive?

Abbiamo implementato uno stack ricorsivo, autoindicato per una class di gestione dei download, come questo:

-(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]; } 

OK, questo è un esempio di una ansible chiamata ricorsiva di diversi download di networking (ad esempio, ottieni 100 immagini di sfarfallio) e prova ad get i nuovi dopo 1 ora, ad esempio. Scusa qualsiasi errore di codifica.

Stiamo eseguendo questo sotto ARC per dispositivi iOS sopra iOS 5.0

Ovviamente abbiamo rotto il primo livello del ciclo di conservazione utilizzando un puntatore di riferimento weakSelf quando si utilizza self.downloadManager mantenendo un riferimento al block di completamento riuscito e non riuscito. Tutto va bene e va bene negli strumenti.

Ora, guardando l'allocazione in Strumenti, lanciamo un'operazione di download per diversi download. Gli strumenti non mostrano perdite. MA, quando si salva regolarmente l'heap, è ansible vederlo crescere lentamente.

Controllando le allocazioni e dando un'occhiata allo stack delle chiamate, sembra che il block stia mantenendo un riferimento a se stesso attraverso l'uso di startDownloadTimer

Qualsiasi spiegazione su una ansible causa e soluzione sarà molto apprezzata 🙂

Solutions Collecting From Web of "Ciclo di completamento della networking, ricorsione e ciclo di conservazione ARC"