2009-06-08 10 views
2

Ich habe zwei Klassen, ClassA, die ClassB instanziieren und eine Methode als Delegat übergeben. ClassB wird schließlich den Delegaten von ClassA aufrufen. Muss ich eine Rücklage für ClassA hinzufügen, wenn ClassB sie speichert?Referenzzählung beim Implementieren eines Delegaten für die benutzerdefinierte Klasse in ObjectiveC

Ich folge der "Implementieren eines Delegaten für eine benutzerdefinierte Klasse" aus dem "Cocoa Fundamentals Guide: Kommunikation mit Objekten", aber der Beispielcode scheint Speicherverwaltung nicht berücksichtigt.

ClassA wird den Delegaten festlegen und erwartet, später wieder aufgerufen zu werden, wenn ClassB mit seiner Arbeit fertig ist.

@implementation ClassA 

-(void)launchSomething 
{ 
    ClassB *classB = [[ClassB alloc] init]; 
    [classB setCallback:self withSelector:@selector(deferredWork)]; 

    // do some other stuff, assign class B to some View and eventually release class B 
} 

-(void)deferredWork 
{ 
    NSLog(@"this is the method that will be deferred till some point in time"); 
} 

Header-Datei für die Klasse B, die gespeichert werden und dann später den Delegaten aufrufen:

@interface ClassB 

id targetObject; 
SEL targetMethod; 

-(void) setCallback:(id)anObject withSelector:(SEL)aMethod 

ClassB Implementierung:

@implementation ClassB 
-(void) setCallback:(id)anObject withSelector:(SEL)aMethod 
{ 
    // QUESTION: Do I need to add a 'retain' here on the targetObject? 
    targetObject = anObject; 
    targetMethod = aMethod; 
} 

-(void) someWorkLater 
{ 
    if ([targetObject respondsToSelector:@selector(targetMethod)]) { 
     // invoke the target object with the specific method 
     [targetObject targetMethod]; 
    } 
} 

Antwort

2

Sie würden nicht behalten KlasseA in ClassB, weil ClassA besitzt bereits ClassB und es wird davon ausgegangen, dass ClassA bei der Aufhebung von ClassA dafür sorgt, dass alle Referenzen in ClassB aufgeräumt werden.

Wenn Sie die "normalen" Besitzregeln befolgten und ClassA beim Festlegen der Delegate-Methode in ClassB beibehalten, würden Sie mit einer Retain-Schleife enden, bei der keine Objekte freigegeben werden. Stattdessen sollten Sie eine schwache Referenz genau wie Sie verwenden.

0

Wie Marc sagte, ist die normale Praxis in Cocoa, dass die Delegierten "schwache" Links sind. Das heißt, sie werden nicht beibehalten. Es ist Aufgabe des Delegaten sicherzustellen, dass, wenn er nicht mehr als Delagate reagieren kann, nichts Schlimmes passiert - entweder durch Setzen des Delegaten auf null oder durch Freigeben des Quellobjekts (vorausgesetzt, es ist der einzige Besitzer und wird sofort freigegeben) .

Also in Ihrem Beispiel, wenn Klasse B bleibt nach dem Ende von LaunchSomething, dann haben Sie es vermutlich in einem ivar gespeichert. Ihre dealloc Routine für classA würde entweder

[classB setCallback:nil]; // optionally withSelector:@selector(none) 

und/oder

[classB release]; 

Wenn classB andere Besitzer haben könnte, dann sollten Sie auf jeden Fall die setCallback verwenden: null, aber oft wissen Sie, Sie sind der einzige Inhaber.

Dinge werden kompliziert, wenn es Ansichten und Fenster gibt, da es schwierig sein kann sicherzustellen, dass die Auftragsobjekte freigegeben werden und niemand sonst eine starke Verbindung zu Klasse B hat. In diesem Fall ist das Löschen des Rückrufs unerlässlich.

Das selbe gilt für Beobachter und Benachrichtigungen, die normalerweise schwache Verbindungen sind und so viel in Ihrer dealloc Routine gelöscht werden.

Verwandte Themen