Spätes, mehrfaches Laden einer Nib

  • Spätes, mehrfaches Laden einer Nib

    Hallo,

    bezugnehmend auf diesen Thread: osxentwicklerforum.de/thread.php?threadid=5435 möchte ich eine Frage bzgl. der Speicherverwaltung stellen.

    Vorhanden ist eine Nib mit einem Fenster und einem dazugehörigen Controller (ControllerA). Auf dem Fenster ist ein Button, der auf Klick eine Action im Controller (A) triggert. Die Action soll einen weiteren Controller (ControllerB) erzeugen, der dann automatisch eine weitere Nib lädt. Klickt der User nochmals auf den Button soll der Controller (B) wieder erzeugt werden und die Nib nochmals laden. Das zu realisieren ist ja kein Problem - aber dies so zu gestalten, dass das Ganze keine Memorymanagementfehler enthält ist nicht so einfach - für mich.

    Hier mein Versuch:

    ControllerAs Action zum Erzeugen des ControllerB:

    Quellcode

    1. - (IBAction)controllerBErzeugenUndSeinFensterAnzeigen:(id)sender {
    2. if([self controllerB] != nil) {
    3. [controllerB release];
    4. }
    5. ControllerB *newControllerB = [[[ControllerB alloc] init] autorelease];
    6. [self setControllerB:newControllerB];
    7. }


    Also - controllerB ist eine Instanzvariable vom Typ ControllerB. ControllerAs init-Methode setzt controllerB auf nil. Klickt der User nun auf den Button wird die Action getriggert. Falls controllerB noch nil ist bedeutet dies, dass er ControllerB erzeugt werden muss. Ist er ungleich nil bedeutet es, dass es schon einen ControllerB geben muss, der allerdings nicht benötigt wird -> ihm wird ein release geschickt.

    Im dealloc von ControllerA wird controllerB, falls dieser != nil released.

    Ist das so okay? Bin mir da total unsicher, ob das so die gängige Praxis ist...
    Die Objective-Cloud ist fertig wenn sie fertig ist. Beta heißt Beta.

    Objective-C und Cocoa Band 2: Fortgeschrittene
    Cocoa/Objective-C Seminare von [co coa:ding].
  • RE: Spätes, mehrfaches Laden einer Nib

    Grundsätzlich machst du alles wie sonst. Du musst nur eine Sache bedenken: Die Top-Level-Objects werden mit einem RC von 1 erzeugt, der *nicht* aus einem ARP stammt. Das ist also so wie ein +alloc-init.

    Lass dir daher beim Laden des Nibs die Top-Level-Objects zurückgebben und speichere sie über einen normalen Setter in einer Instanzvariable des Controllers. Jetzt hast du sie persönlich retaint. Also muss nur noch ein release oder autorelease her. Hierzu schickst du an alle Mitglieder der Top-Level-Objects-Collection ein -release:

    Quellcode

    1. - (NSArray*)loadNibFile:(NSString*)file {
    2. NSBundle* bundle = [NSBundle mainBundle];
    3. NSMutableArray* newTopLevelObjects = [NSMutableArray array];
    4. NSDictionary* nameTable = [NSDictionary dictionaryWithObjectsAndKeys:
    5. [self unproxy], NSNibOwner,
    6. newTopLevelObjects, NSNibTopLevelObjects,
    7. nil];
    8. if (![bundle loadNibFile:file externalNameTable:nameTable withZone:nil]) {
    9. NSLog(@"Missing %@.NIB!", file);
    10. return nil;
    11. }
    12. [newTopLevelObjects makeObjectsPerformSelector:@selector( autorelease )];
    13. [self setTopLevelObjects:newTopLevelObjects];
    14. [self setPane:file];
    15. return topLevelObjects;
    16. }
    Alles anzeigen
    BTW: Das -autorelease kannst du durch ein -release ersetzen, wenn du lustig bist.

    Noch etwas: In diesem Code wird ein Nib mit Views nachgeladen, der den Lader als File's Owner bekommt. Das führt dazu, dass -awakeFromNib des Laders *erneut* aufgerufen wird. Ich merke mir daher im -awakeFromNib, ob ich schon einmal gelaufen bin, um Dinge nicht doppelt zu erledigen, die nur einmal erledigt werden sollten.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?