2013-07-27 4 views
6

Der folgende Code stammt aus dem von Apple bereitgestellten LazyTableImages-Beispielcode (source here).Capture selbst in Block (Retain-Zyklen), nicht immer?

In ihrem Komplettierungsblock haben sie einen Verweis auf self, der einen Retain-Zyklus verursachen sollte ... Aber dafür bekomme ich keine Warnung in Xcode, während ich in ähnlichem Code von mir würde.

Ist das korrekt?

Vielleicht vermisse ich eine Feinheit davon.

- (void)startIconDownload:(AppRecord *)appRecord forIndexPath:(NSIndexPath *)indexPath 
{ 
    IconDownloader *iconDownloader = [self.imageDownloadsInProgress objectForKey:indexPath]; 
    if (iconDownloader == nil) 
    { 
     iconDownloader = [[IconDownloader alloc] init]; 
     iconDownloader.appRecord = appRecord; 
     [iconDownloader setCompletionHandler:^{ 

      UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath]; 

      // Display the newly loaded image 
      cell.imageView.image = appRecord.appIcon; 

      // Remove the IconDownloader from the in progress list. 
      // This will result in it being deallocated. 
      [self.imageDownloadsInProgress removeObjectForKey:indexPath]; 

     }]; 
     [self.imageDownloadsInProgress setObject:iconDownloader forKey:indexPath]; 
     [iconDownloader startDownload]; 
    } 
} 
+1

mögliches Duplikat von [Möglich, \ [self anyFunction \] in Blöcken ohne \ _ \ _ schwaches Objekt (iOS 5 + ARC) zu übergeben] (http://stackoverflow.com/questions/9003600/possible-to-pass- self-anyfunction-in-blocks-ohne-schwach-objekt-ios-5-arc), Sorry Daniel :) – Abizern

+0

Sie sagen, dass es keine Warnung gibt, weil es mehr als eine Ebene im Zyklus gibt, @Abizer? –

+0

Es gibt keine Warnung, da es keinen Retain-Zyklus gibt. – Abizern

Antwort

4

Der Aufbewahrungszyklus, den Sie zu sehen glauben, liegt daran, dass das Objekt den Downloader in einem Wörterbuch enthält.

Es ist wahr, dass es im Block einen starken Verweis auf self gibt, aber solange der Vervollständigungshandler immer ausgeführt wird, wird der Downloader aus dem Wörterbuch entfernt. Und schließlich wird dieses Wörterbuch leer sein, was bedeutet, dass es keine Objekte geben wird, die sich selbst festhalten und somit keinen Retain-Zyklus.

+2

Der Compiler verwendet Benennungskonventionen, um zu entscheiden, ob vor einem möglichen Zurückhaltezyklus gewarnt werden soll oder nicht. Vergleichen Sie [Clang - Blocks retain cycle from naming convention?] (Http://stackoverflow.com/questions/15535899/clang-blocks-retain-) Cycle-from-Naming-Konvention). –

0

self keinen starken Zeiger auf iconDownloader haben. Es erstellt und scoped gerade zu dieser Methode:

IconDownloader *iconDownloader = [self.imageDownloadsInProgress objectForKey:indexPath]; 

Wenn iconDownloader eine starke Eigenschaft war (self.iconDownloader) dann Xcode würde einen starken Referenzzyklus erkennen.

+0

Das 'iconDownloader'-Objekt scheint' imageDownloadsInProgress' zu gehören, das vermutlich im Besitz von 'self' ist; Wenn der 'iconDownloader 'auch den Abschlussblock übernimmt, dann ist dies ein starker Retain-Zyklus. –

+0

Guter Fang. Ich denke, es gibt hier einen Retain-Zyklus, aber da es ein NSDictionary durchläuft, erzeugt Xcode keine Warnung. –

+0

Nebenbei bemerkt, ist die Verwendung der 'IconDownloader'-Klasse ein Rezept für eine Katastrophe, wenn sich Ihre Daten häufig ändern. Sie sollten den 'indexPath' nicht verwenden, um zu bestimmen, wo Sie Ihr Image nach dem Download speichern können, wenn sich Ihre Daten möglicherweise bei einem anderen Indexpfad befinden, wenn das Image heruntergeladen wird. –

0

Capture Selbst selbst ist kein Retain-Zyklus. Es ist eine einzige Referenz. Eine Referenz kann keinen Zyklus erstellen. Das übliche Antipattern ist, dass zusätzlich eine Referenz auf den Block in einer starken Eigenschaft des Selbst gespeichert wird. Dann gibt es zwei Referenzen, die einen Zyklus aufbauen.

0

Es gibt keine Warnung, da der Compiler noch nicht alle möglichen Aufbewahrungszyklen erkennen kann.

Zum Beispiel:

- (void)foo 
{ 
    _block =^{ [self done]; }; // Warning: Possible retain cycle 

    DSGenericBlock foo =^{ [self done] }; 
    _block = foo; // No warning. 
} 

Wenn Sie den Block direkt auf eine Instanz Variable der „Selbst“ zuzuordnen sind, würden Sie die „möglich beibehalten Zyklus“ Warnung. Stattdessen wird der Block einem anderen Objekt zugewiesen, das dann von self beibehalten wird, so dass der Compiler den Zyklus nicht erkennt (obwohl der Zyklus existiert).

+1

Es gibt keine Warnung, da es keinen Retain-Zyklus gibt. – Abizern

Verwandte Themen