Im Block niemals nie iVars oder 'self' verwenden?

  • Im Block niemals nie iVars oder 'self' verwenden?

    WWDC '12 Session #242 "iOS App Performance: Memory"

    Denn der Compiler macht aus dem "self" eine strong-Variable und ihr habt ein Speicherleck.
    Unter ARC könnt ihr das retain vermeiden, indem ihr vor dem Block eine Weak-Variable erstellt:

    __weak id weakSelf = self;

    bzw. unter MRC

    __block id blockSelf = self;

    und dann im Block die Variable (weakSelf bzw. blockSelf) anstelle des 'self' verwendet.

    Aus der iVar wird ebenfalls eine strong-Variable, daher Properties verwenden!

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von DroneDeveloper () aus folgendem Grund: NDA-Material endgültig entfernt

  • Mir ist immer noch nicht klar, wann und wie Blöcke Variablen behandeln.
    In meinem Fall ist es MRC.
    Folgende Praxisbeispiele:

    Quellcode

    1. (1) dispatch_after(when, dispatch_get_main_queue(), ^(void) {
    2. self.textField.text = @"";
    3. [[UIApplication sharedApplication] endIgnoringInteractionEvents];
    4. });
    5. typedef BOOL (^GCPasscodeVerifyBlock) (NSString *code);
    6. (2) pinViewController.verifyBlock = ^(NSString *code) {
    7. NSDictionary *entry = (NSDictionary *)[self.entries objectAtIndex:self.index];
    8. BOOL value = [code isEqualToString:(NSString *)[entry objectForKey:@"code"]];
    9. if (value) {
    10. if (self.imageView.image) {
    11. self.button.alpha = 0.7;
    12. }
    13. }
    14. return value;
    15. }
    16. (3) [UIView animateWithDurarion:0.2 animations:^(void) {
    17. for (UIView *subview in self.view.subviews) {
    18. CGRect frame = subview.frame;
    19. frame.origin.x += self.view.frame.size.height;
    20. subview.frame = frame;
    21. }
    22. }];
    23. ViewController *viewController = [[ViewController alloc] init];
    24. CGFloat alpha = viewController.view.alpha;
    25. viewController.view.alpha = 0;
    26. (4) [UIView animateWithDuration:0.2 animations:^(void) {
    27. viewController.view.alpha = alpha;
    28. }];
    Alles anzeigen


    So habe ich es bisher gelöst. Nach dem Vortrag habe ich in jedem Block das "self" ersetzt, das kam mir aber gleich spanisch vor.
    Was meint ihr?
  • Die Problematik ist ja eigentlich nur bei ARC relevant, da du unter MRC deine retains und releases selbst bestimmst und nicht der Compiler.

    Unter ARC würde in (1), (3) und (4) der Block (und damit self bzw. viewController) nur für die Zeit der Ausführung gehalten und anschließend wieder freigegeben -> also kein Leak.
    Bei (2) wird der Block und damit self so lange gehalten, bis pinViewController den Block wieder frei gibt (vorausgesetzt es handelt sich bei verifyBlock um ein strong/retain Property). Ob das in einem Leak mündet ist eine Frage der Abhängigkeiten zwischen self und pinViewController und/oder der Lebenszeit von pinViewController.

    Darum sollte man sich an Apples Tipp halten und unter ARC immer die "Ownership" betrachten:
    - die Verwendung von self oder einer ivar innerhalb eines Blocks überträgt die Ownership an den Block
    - die Übergabe eines Blocks überträgt die Ownership an den Empfänger des Blocks

    Bei den von dir angeführten Observing-Beispielen von Apple führt das Übertragen der Ownership von self über den Block an das NotificationCenter dazu, dass self niemals freigegeben würde, solange es als Observer im NotificationCenter angemeldet ist.
    Das wäre quasi so, als würde das NotificationCenter seine Observer retainen, was es zum Glück nicht tut! :)