2011-08-31 7 views
17

powiedziano mi przez fellow StackOverflow user że nie powinien podczas zwalniania właściwość wykorzystać metodę getter:Dlaczego nie powinienem używać gettera do zwolnienia właściwości w obiekcie -c?

@property(nonatmic, retain) Type* variable; 
@synthesize variable; 

// wrong 
[self.variable release]; 

// right 
[variable release]; 

Nie szczegółowo wyjaśnić dlaczego. Wydają mi się takie same. My iOS book powiedział getter na nieruchomości będzie wyglądać następująco:

- (id)variable { 
    return variable; 
} 

Więc nie oznacza to [self variable], self.variable i variable wszystkie są takie same?

+0

To bardzo niebezpieczne zalecenie; getter nie zawsze tak będzie wyglądać. W rzeczywistości, gdyby była to własność "atomowa", to -retain/-autorelease. – bbum

Odpowiedz

4

Typowym getter będzie wyglądać mniej więcej tak:

- (id)variable { 
    return [[variable retain] autorelease]; 
} 

Więc jeśli używasz [self.variable release] masz dodatkową retain i autorelease że tak naprawdę nie potrzeba, gdy po prostu chcesz zwolnić przedmiotu oraz powodujących obiekt, który ma zostać zwolniony później niż jest to konieczne (gdy pula autoreleaseu zostanie opróżniona).

Zazwyczaj chcesz użyć self.variable = nil który ma tę zaletę, że również ustawia zmienną nil (unikanie wypadków z powodu błędnych odwołań) lub [variable release] który jest najszybszy i może być bardziej odpowiednie w sposobie dealloc jeśli seter ma niestandardową logikę.

9

Możesz opcjonalnie napisać niestandardowe zachowanie gettera, co może skutkować zupełnie innym zachowaniem. Tak więc nie zawsze można założyć, że [variable release] ma takie same wyniki jak [self.variable release].

Można również pisać niestandardowe właściwości bez wyłącznego ivar, który je wspiera ... może stać się niechlujny, jeśli zaczniesz zwalniać obiekty z referencji zwróconych przez moduły pobierające!

mogą występować dodatkowe powody, że jestem nieświadomy ...

+0

To prawda, ale nie mogę sobie wyobrazić, jaki rodzaj gettera zmieniłby właściwość w taki sposób, w jaki użytkownik nie mógłby go zwolnić.) – Eimantas

+1

@Eimantas: Nie mogę jednak powiedzieć, że wypuszczasz obiekty przez gettery w twoim dealloc ... Kod napisany w niestandardowym geterze może próbować uzyskać dostęp do innych plików ivar, które zostały już wydane, powodując awarię. Lub inne dziwne przypadki takie jak to! – MechEthan

+3

Może getter może zwrócić autologiczną kopię? Byłby to okropny pomysł, ale i tak byłby ważny. Następnie, w takim przypadku, zwolnienie wartości zwróconej przez getter spowodowałoby awarię twojego programu przez nadmierne zwolnienie obiektu. –

13

Dla zatrzymanego mienia bez niestandardowego akcesor można zwolnić obiekt przez:

self.variable = nil; 

Ma to wpływ ustawiając ivar (który może nie być nazywany "zmienną", jeśli masz tylko zadeklarowane właściwości), aby zerować i zwalniać poprzednią wartość.

Jak już inni zauważyli, albo bezpośrednio zwalniając ivar (jeśli jest dostępny), albo używając powyższej metody jest OK - czego nie wolno robić, to wywołanie wydania na zmiennej zwróconej z pobierającego.

+0

Wiedziałem, że zapomniałem czegoś ważnego w mojej odpowiedzi ... przejąłem waszą, ponieważ jest to ważna rzecz do zrozumienia! – MechEthan

+0

Czytam w [wielu miejscach] (http://stackoverflow.com/questions/5737312/set-to-nil-in-viewdidunload- but-release-in-dealloc/5737438#5737438), że właściwości powinny być wydane w ' dealloc' i ustawiony na zero w 'viewDidUnload'. – JoJo

+1

Jeśli masz również ivar, możesz to bezpośrednio zwolnić. Chodzi o to, że nie możesz zwolnić tego, co jest zwracane przez getter, ponieważ nie gwarantuje to, że jest prawdziwą zmienną bazową. Bezpośrednie zwolnienie ivar zapobiega jakiejkolwiek niestandardowej logice w ustawianiu, jeśli nie ma żadnych, robi niewielką różnicę. – jrturton

4

nie wszystkie getters wziąć tę postać:

- (id)variable { return variable; } 

... to jest po prostu najbardziej prymitywna forma. same właściwości powinny sugerować więcej kombinacji, które zmieniają implementację. powyższy prymitywny akcesor nie uwzględnia idiomów używanych w połączeniu z zarządzaniem pamięcią, atomowością lub semantyką kopiowania. implementacja jest również delikatna w nadpisaniach podklas.

kilka naprawdę krótkich przykładów; rzeczy oczywiście stają się bardziej złożone w prawdziwych programach, w których implementacje stają się znacznie bardziej złożone.

1) getter może nie zwrócić zmiennej instancji.jedna z kilku możliwości:

- (NSObject *)a { return [[a copy] autorelease]; } 

2) Seter może nie zachować zmiennej instancji. jedna z kilku możliwości:

- (void)setA:(NSObject *)arg 
{ 
    ... 
    a = [arg copy]; 
    ... 
} 

3) skończyć z wdrożenia zarządzania pamięcią w całym programie, co sprawia, że ​​trudno jest utrzymać. semantyka klasy (i jak obsługuje ref liczenia Instancji zmiennych) powinno być ograniczone do klasy i postępuj konwencje dla oczekiwanych wyników:

- (void)stuff:(NSString *)arg 
{ 
    const bool TheRightWay = false; 
    if (TheRightWay) { 
     NSMutableString * string = [arg mutableCopy]; 
     [string appendString:@"2"]; 
     self.a = string; 
     [string release]; 
     // - or - 
     NSMutableString * string = [[arg mutableCopy] autorelase]; 
     [string appendString:@"2"]; 
     self.a = string; 
    } 
    else { 
     NSMutableString * string = [arg mutableCopy]; 
     [string appendString:@"2"]; 
     self.a = string; 
     [self.a release]; 
    } 
} 

niestosowanie się do tych prostych zasad sprawia, że ​​kod trudne do utrzymania i debugowania i bolesne do rozszerzenia.

więc najtrudniej jest, aby program był łatwy w utrzymaniu. wywoływanie zwalniania bezpośrednio na obiekcie wymaga znajomości wielu kontekstów wewnętrznych działań klasy; to oczywiście źle i brakuje dobrych ideałów dobrego OOD.

oczekuje również od autorów/subklasujących/klientów, aby dokładnie wiedzieli, w jaki sposób klasa odstaje od konwencji, co jest głupie i czasochłonne, gdy pojawiają się problemy i musisz ponownie nauczyć się wszystkich wewnętrznych szczegółów, gdy pojawiają się problemy (będą one w pewnym momencie).

to niektóre z trywialnych przykładów na to, w jaki sposób wywoływanie wersji z wyników właściwości wprowadza problemy. wiele problemów w świecie rzeczywistym jest znacznie trudniejszych do zlokalizowania.

Powiązane problemy