2010-10-13 10 views
5

Mam następujący w nagłówku:W jaki sposób zaimplementowano metodę ustawiającą zatrzymanie za pomocą @synthesize?

@property (nonatomic, retain) UIView *overlay; 

A w realizacji:

@synthesize overlay; 

wówczas:

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

nie jest zmienną tempOverlay powyżej niepotrzebne? Nie mogę po prostu zrobić:

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

Odpowiedz

11

syntetyzowane zachowane setter wygląda następująco:

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

W twoim przypadku masz dwie ważne metody:

1) Tworzenie temp var alloc/init (= zachowane), zestaw do nieruchomości , wydanie.

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

2) Bez temp var, ustaw bezpośrednio na ivar.

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

UPDATE: Jeśli używasz metody 2), trzeba jawnie obsłużyć resztę zarządzania pamięcią (nie tylko oporowe), zwalniając każdą poprzednią wartość może mieć przed razie potrzeby. Jeśli zrobione tylko raz w init (na przykład), możesz po prostu umieścić [overlay release]; w dealloc.

+0

Jeśli syntetyzowany zachowany ustawiający wygląda tak, jak go masz, to co dzieje się po pierwszym ustawieniu wartości? Jeśli spróbujesz najpierw zwolnić starą wartość, czy nie nastąpi awaria z NIEPOPRAWNYM DOSTĘPEM? Czy wszystkie właściwości automatycznie otrzymują początkową liczbę zatrzymań wynoszącą 1? – ma11hew28

+0

Czy metoda 2) kiedykolwiek zostanie wykorzystana, być może po raz pierwszy zostanie ustawiona? Ale jeśli ustawisz to po ustawieniu, to stara wartość nie zostanie zwolniona (chyba że zostanie to wyraźnie określone). To może spowodować wyciek pamięci, prawda? – ma11hew28

+2

Początkowo wartość jest zerowa, a wysłanie dowolnej wiadomości do zera (łącznie z zachowaniem/zwolnieniem) jest zerową liczbą zero. – jv42

2

Korzystanie atrybut retain określa, że ​​retain powinny być powoływane na nowym obiekcie, a poprzednia wartość jest wysyłany release.

W drugim bloku kodu liczba zatrzymań obiektu wynosiłaby 2, ponieważ już go nie zwolnisz, a ustawiający je zachowuje. To raczej nie jest to, czego chcesz.

-2

Tak, można bezpośrednio przypisać nowo utworzony obiekt do obiektu overlay. Jeśli chcesz, możesz udowodnić to do siebie, drukując liczbę utrzymania obiektu

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

-1 Tęsknisz za punktem. Obiekt został utworzony z przydziału. Dlatego należysz do niego i musisz go uwolnić, kiedy skończysz, co masz natychmiast w tym przypadku. – JeremyP

+0

Nie sądzę. Zobacz odpowiedź, którą dałem. – ma11hew28

1

jeśli przypisać obiekt bezpośrednio do nieruchomości, nadal musi ją zwolnić:

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

To musi być niepoprawne. Zobacz odpowiedź, którą dałem. – ma11hew28

+0

Niestety, nie przewinąłem w prawo, aby zobaczyć autorelease. To jest poprawne rozwiązanie, ale chciałem jawnie zwolnić wartość temp po ustawieniu 'overlay'. – ma11hew28

1

Jak Twój dom jest zdefiniowana (zachowują) dowolną instancję ustawionego za pomocą zsyntetyzowany setter (za pomocą składni self.overlay) zostanie automatycznie wysłana wiadomość o zatrzymaniu:

// 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]; 

Jeśli było zrobić:

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

Nakładka będzie miała zachowane dwie liczby, co prawdopodobnie doprowadzi do wycieku w pewnym momencie w aplikacji.

0

Dziękuję za wszystkie odpowiedzi.Mam kilka sprzecznych roszczeń więc przetestowane następujące składniki w 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; 
} 

mam następujący wyjście konsoli:

  • Czasami prowadził dobrze:

    count: 0 
    count: 2 
    released once 
    count: 1 
    released twice 
    count: 1 
    
  • Inne razy rozbił się:

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

Wiem, że metoda z użyciem tempOverlay jest poprawna. To po prostu wydaje się być uciążliwe, ale wolę to od autorelease, ponieważ nie rozumiem, jak działa autorelease lub kiedy jest wywoływane. Jedno jest pewne. Powyższy kod jest nieprawidłowy, ponieważ nie chcę, aby overlay miał zachowaną liczbę 2.

Dziwne jest to, że nie mogę tego zwolnić dwa razy. Nawet jeśli się nie zawiesza, liczba zatrzymań nie maleje.

W każdym razie, zgaduję, że będę teraz używał tempOverlay.

+0

o liczbie zatrzymań 2 jest poprawna w kodzie, który masz. raz dla iVar zachować i ponownie dla wywołania "alloc". – johnbakers