10

Ich arbeite an einer iPad Photo Collage App, die vielleicht Hunderte von UIImageView s auf dem Bildschirm auf einmal zeichnet.Erzwingen, dass ein Objekt unter ARC freigegeben wird

Es gibt eine Schaltfläche, die den Benutzer "re-create" ermöglicht, die eine for Schleife auf [photo removeFromSuperview] auf allen Fotos ausführen und dann eine neue Charge in dieser Reihenfolge initialisieren soll.

Ich bin mit ARC, und meine Konsole sagt mir, dass meine Photo ‚s dealloc Methode wird erst nach der nächsten Charge genannt gezogen worden ist, was bedeutet, ich in den Speicher Probleme renne, obwohl ich bin versuchen, den ersten Satz vor dem Hinzufügen des nächsten Satzes zu entfernen.

Gibt es eine Möglichkeit, entweder 1) zu warten, bis alle Fotos korrekt freigegeben wurden oder 2) alle Fotos sofort unter ARC zum Dealloc zu zwingen?

+1

Radu hat recht, wenn Sie die Bildansichten entfernen und alle starken Verweise auf diese entfernen, werden sie sofort freigegeben. Es ist nicht wie bei dem alten MRC-Problem, bei dem die schlampige Verwendung von "Autorelease" zu einer Verzögerung der Freigabe des Speichers bis zum Ende der aktuellen Ausführungsschleife führen könnte. Wenn Sie immer noch Probleme haben, müssen Sie uns Code-Snippet zeigen, wie Sie Referenzen auf die Bilder und deren Bildansichten erstellen, hinzufügen und speichern. Aber wenn ich die Bildansicht entferne und eine neue erstelle, passiert die Deallok für die alte, bevor ich zur Erstellung der neuen komme. – Rob

Antwort

13

Wahrscheinlich setzen Sie Ihre Bildansichten in einen Autorelease-Pool, ohne es zu merken. Sie können dies möglicherweise beheben, indem Sie Ihren eigenen Autorelease-Pool um Ihre for-Schleife wickeln.

Zum Beispiel habe ich ein sehr einfaches Testprojekt mit einer Bildansicht und einer Schaltfläche unter meiner Top-Level-Ansicht gemacht. Wenn ich auf die Schaltfläche tippe, wird die Bildansicht entfernt und eine neue erstellt. Es entfernt die Bildansicht, indem die Teilansichten der Top-Level-Ansicht durchlaufen werden. Hier ist der Code:

@implementation ViewController 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    [self initImageView]; 
} 

- (IBAction)redoWasTapped:(id)sender { 
    [self destroyImageView]; 
    [self initImageView]; 
} 

- (void)destroyImageView { 
    for (UIView *subview in self.view.subviews) { 
     if ([subview isKindOfClass:[UIImageView class]]) { 
      [subview removeFromSuperview]; 
     } 
    } 
} 

- (void)initImageView { 
    UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"picture.jpg"]]; 
    imageView.frame = CGRectInset(self.view.bounds, 100, 100); 
    [self.view addSubview:imageView]; 
} 

@end 

Als ich lief dies unter dem Verrechnungen Instrument mit „Record Referenzzähler“ aktiviert ist, ich sah, dass jede entfernte Bildansicht nicht während destroyImageView ausgeplant. Stattdessen wurde es später freigegeben, wenn die Ausführungsschleife -[NSAutoreleasePool release] aufgerufen wurde.

Dann änderte ich destroyImageView seinen eigenen Autofreigabepool zu verwalten:

- (void)destroyImageView { 
    @autoreleasepool { 
     for (UIView *subview in self.view.subviews) { 
      if ([subview isKindOfClass:[UIImageView class]]) { 
       [subview removeFromSuperview]; 
      } 
     } 
    } 
} 

Als ich es unter Instrumente wieder lief, sah ich, dass jede entfernte Bildansicht während destroyImageView, am Ende des @autoreleasepool Block freigegeben wurde.

+0

Um es zu verstehen, lesen Sie über [ NSAutoreleasePool und Run Loops] (https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html) – DanSkeel

9

ARC dealloc s jedes Objekt, für das keine starken Referenzen mehr vorhanden sind. So zu dealloc etwas, setzen Sie einfach alle Variablen, die darauf zeigen, nil und stellen Sie sicher, dass das Objekt nicht in einem Zirkelbezug beteiligt ist.

+3

Entspricht es sofort, nachdem keine Referenzen mehr vorhanden sind, oder wird es später einfach freigegeben? Empirisch scheint es sofort zu geschehen, aber gibt es dafür eine Garantie? Und wenn nicht, erzwingt das Setzen auf Null kein Dealloc. – prewett

+0

Um zu verstehen, lesen Sie über [NSAutoreleasePool und Run Loops] (https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html) – DanSkeel