2010-10-13 3 views
5

Ich habe im Anschluss an die in der Kopfzeile:Wie wird Retain Setter mit @synthesize implementiert?

@property (nonatomic, retain) UIView *overlay; 

Und bei der Umsetzung:

@synthesize overlay; 

Dann:

UIView *tempOverlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)]; 
self.overlay = tempOverlay; 
[tempOverlay release]; 

Sind nicht die tempOverlay Variable oben überflüssig? Kann ich nicht tun, nur:

self.overlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)]; 

Antwort

11

A synthetisiert beibehalten Setter wie folgt aussieht:

- (void)setValue: (id)newValue 
{ 
    if (value != newValue) 
    { 
     [value release]; 
     value = newValue; 
     [value retain]; 
    } 
} 

In Ihrem Fall Sie zwei gültige Methoden haben:

1) Erstellen Sie eine temporäre var, alloc/init (= beibehalten), auf Eigentum , Freisetzung.

IView *tempOverlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)]; 
self.overlay = tempOverlay; 
[tempOverlay release]; 

2) Keine Temp var, direkt auf ivar gesetzt.

overlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)]; 

UPDATE: Wenn Sie Methode 2), müssen Sie explizit den Rest der Speicherverwaltung behandeln (nicht nur beibehalten), durch den vorherigen Wert loslassen haben könnte, bevor, wenn nötig. Wenn nur einmal in init (zum Beispiel) getan, können Sie einfach eine [overlay release]; in dealloc setzen.

+0

Wenn ein synthetischer beibehaltener Setter so aussieht, wie Sie ihn haben, was passiert beim ersten Mal, wenn der Wert gesetzt wird? Wenn Sie versuchen, den alten Wert zuerst freizugeben, stürzt es nicht mit BAD ACCESS ab? Oder erhalten alle Eigenschaften automatisch eine anfängliche Retain-Anzahl von 1? – ma11hew28

+0

Sollte Methode 2) jemals verwendet werden, vielleicht beim ersten Mal? Wenn Sie es jedoch festlegen, nachdem es bereits festgelegt wurde, wird der alte Wert nicht freigegeben (sofern nicht explizit angegeben). Also, das würde einen Speicherverlust verursachen, richtig? – ma11hew28

+2

Anfangs ist der Wert null, und das Senden einer Nachricht an null (einschließlich Retain/Release) ist ein Nein, das nil zurückgibt. – jv42

2

Mit dem retain Attribute gibt an, dass retain sollte auf das neue Objekt aufgerufen werden, und der vorherige Wert wird ein release gesendet.

Also in Ihrem zweiten Codeblock würde die Retain-Anzahl des Objekts 2 werden, da Sie es nicht mehr freigeben, und der Setter behält es. Dies ist wahrscheinlich nicht das, was Sie wollen.

-2

Ja, Sie können das neu erstellte Objekt direkt dem Objekt overlay zuweisen. Wenn Sie möchten, können Sie es sich selbst beweisen, indem sie die Zählung behalten Druck aus dem Objekt

NSLog(@"count: %d", [overlay retainCount]); 
+0

-1 Sie verpassen den Punkt. Das Objekt wurde mit alloc erstellt. Sie besitzen es daher und müssen es freigeben, wenn Sie damit fertig sind, das Sie in diesem Fall sofort sind. – JeremyP

+0

Ich glaube nicht. Siehe die Antwort, die ich gab. – ma11hew28

1

Wenn Sie das Objekt direkt an die Eigenschaft zuweisen, noch müssen Sie ihn freigeben:

self.overlay = [[[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)] autorelease]; 
+0

Dies muss falsch sein. Siehe die Antwort, die ich gab. – ma11hew28

+0

Entschuldigung, ich habe nicht nach rechts geblättert, um die 'Autorelease' zu ​​sehen. Dies ist eine korrekte Lösung, aber ich wollte den Temp-Wert nach dem Setzen von 'overlay' explizit freigeben. – ma11hew28

1

Wie Ihr Eigentum ist mit (behalten) jede Instanz, die Sie die synthetisierte Setter mit set definiert (über die self.overlay Syntax) wird automatisch eine behalten Nachricht gesendet werden:

// You're alloc'ing and init'ing an object instance, which returns an 
// instance with a retainCount of 1. 
UIView *tempOverlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)]; 

// The overlay property is defined with (retain), so when you assign the new 
// instance to this property, it'll automatically invoke the synthesized setter, 
// which will send it a retain message. Your instance now has a retain count of 2. 
self.overlay = tempOverlay; 

// Send a release message, dropping the retain count to 1. 
[tempOverlay release]; 

Wenn Sie tun, waren:

self.overlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)]; 

Ihr Overlay würde eine Retain-Zahl von zwei haben, was wahrscheinlich zu einem Leck in Ihrer Anwendung führen wird.

0

Vielen Dank für alle Antworten.Ich habe einige widersprüchliche Ansprüche so testete ich die folgenden in einem UITableViewController:

- (id)initWithStyle:(UITableViewStyle)style { 
    if ((self = [super initWithStyle:style])) { 
     NSLog(@"count: %d", [overlay retainCount]); 
     self.overlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)]; 
     NSLog(@"count: %d", [overlay retainCount]); 
     [overlay release]; NSLog(@"released once"); 
     NSLog(@"count: %d", [overlay retainCount]);  
     [overlay release]; NSLog(@"released twice"); 
     NSLog(@"count: %d", [overlay retainCount]); 
    } 
    return self; 
} 

habe ich die folgende Ausgabe der Konsole:

  • Manchmal fein es lief:

    count: 0 
    count: 2 
    released once 
    count: 1 
    released twice 
    count: 1 
    
  • Andere Zeiten es stürzte ab:

    count: 0 
    count: 2 
    released once 
    count: 1 
    released twice 
    Program received signal: “EXC_BAD_ACCESS”. 
    

Ich weiß, dass die Methode mit tempOverlay korrekt ist. Es scheint nur so umständlich, aber ich bevorzuge es autorelease, weil ich nicht verstehe, wie autorelease funktioniert oder wann es heißt. Eine Sache ist sicher. Der obige Code ist falsch, weil ich nicht möchte overlay eine Retain-Anzahl von 2 haben.

Die seltsame Sache ist, dass ich es nicht zweimal freigeben kann. Selbst wenn es nicht abstürzt, wird der Retain-Count nicht dekrementiert.

Wie auch immer, ich denke, ich bleibe bei der Verwendung der tempOverlay für jetzt.

+0

mit einer Retain-Anzahl von 2 ist korrekt in dem Code, den Sie haben. einmal für den iVar behalten, und noch einmal für den "alloc" -Aufruf. – johnbakers