Co zrobić, jeśli mam obiekt, powiedzmy NSIndexPath, w którym przed wykonaniem kopii zawsze najpierw go zwalniam?

Czy można mieć liczbę pamięci poniżej 0? Robię to, aby zapobiec wyciekom pamięci.. czy to dobry sposób?

//global ma już wcześniej jakąś wartość tutaj lub nie ma wartości. Chcę zaktualizować
//to z nową wartością (nie obchodzi mnie stary wskaźnik)

 [global release]
 global = [indexPath copy];
1
adit 29 maj 2011, 19:38

2 odpowiedzi

Najlepsza odpowiedź

Nie. Gdy liczba zachowań osiągnie 0, twój obiekt zostanie cofnięty, a jego wskaźnik stanie się nieważny, więc ponowne użycie go spowoduje nieprzewidywalne wyniki (mianowicie awarię).

Należy zapoznać się z Przewodnik zarządzania pamięcią.

Oto podstawowa zasada:

  • Zwalniasz lub automatycznie zwalniasz tylko obiekty, których jesteś właścicielem. Przejmujesz własność obiektu, jeśli utworzysz go za pomocą metody, której nazwa zaczyna się od „alloc”, „new”, „copy” lub „mutableCopy” (na przykład aloc, newObject lub mutableCopy) lub jeśli go wyślesz zachowaj wiadomość.
  • Używasz wydania lub automatycznego wydania, aby zrzec się prawa własności do obiektu. autorelease oznacza po prostu „wyślij wiadomość o wydaniu w przyszłości” (w szczególności: gdy używana pula autorelease otrzyma wiadomość o drenażu).

Aktualizacja:

Jak zauważył Josh, jedynym przypadkiem, który należy wziąć pod uwagę, jest to, że globalna i indexPath są takie same. W takim przypadku nadal będziesz „potrzebował” wskaźnika (do wykonania kopii), więc albo automatycznie zwalniasz (zamiast zwalniania) albo używasz tymczasowej zmiennej do obsługi tego.

8
André Morujão 30 maj 2011, 01:40
4
Jako dodatek do tego posta, patrzenie na keepCount jest prawie zawsze złym rozwiązaniem. Więc nie rób tego, nawet w celach "debugowania".
 – 
jer
29 maj 2011, 19:48
Przeczytałem to.. Właśnie teraz próbuję zapobiec wyciekowi pamięci, ponieważ mam kopię i znajduję trudny moment, kiedy ją zwolnić. Musi zostać zwolniony, zanim zrobię kolejną kopię za pomocą tej zmiennej
 – 
adit
29 maj 2011, 19:48
Wszystko sprowadza się do własności. Kiedy musisz „przejąć na własność” obiekt, zwiększasz jego liczbę zachowanych (niezależnie od tego, czy jest to za pośrednictwem jawnego komunikatu retain, czy też za pomocą alloc, new, copy lub mutableCopy). Kiedy już go nie potrzebujesz, release to. Po prostu zastanów się, kiedy z tym skończysz i wtedy możesz to uwolnić.
 – 
André Morujão
29 maj 2011, 19:51
Myślę, że na pewno rozumiesz, o co mi chodzi, powodem, dla którego wypuszczam, zanim zrobię kopię, jest to, że nie obchodzi mnie już obiekt, ponieważ jestem gotowy, aby uzyskać nowy.. i chcę w ten sposób zapobiec wyciekowi pamięci ... więc czy jest to słuszny punkt? Zaktualizowałem moje pytanie powyżej, aby było jasne
 – 
adit
29 maj 2011, 19:52
1
Jeśli chodzi o automatyczne wydanie, lepiej przeczytaj dokumentację (lub jeśli nadal nie masz pewności, możesz zadać nowe pytanie). Ale przez większość czasu można po prostu myśleć o automatycznym wydaniu jako o „wydaniu na końcu bieżącego cyklu wydarzeń”.
 – 
André Morujão
29 maj 2011, 20:02

To, co robisz, jest zasadniczo poprawne, o ile global ma albo starą wartość, której już nie potrzebujesz, albo jest nil. Jeśli jest to jeden z ivarów klasy, podczas tworzenia instancji klasy będzie to nil. Jedyny haczyk polega na tym, że jeśli nowy indexPath okaże się tym samym obiektem, co ten, który jest już w global, uwolnisz go nadmiernie i ulegnie awarii.

// global points to object at 0x8BADFOOD
// indexPath also happens to be 0x8BADFOOD; for some reason, it
// hasn't changed since last time. This _can_ happen.
[global release];    // object at 0x8BADFOOD is deallocated
global = [indexPath copy];    // indexPath no longer valid! 
                              // Crash! Bang! Boom!

Sposobem na uniknięcie tego jest użycie zmiennej temp.

Kiedy deklarujesz właściwość jako copy i syntetyzujesz tę właściwość, tworzona metoda ustawiająca wygląda zasadniczo tak i możesz zrobić to samo:

- (void)setMyFloozit:(Floozit *)newFloozit {
    // Copy first in case newFloozit and myFloozit are for
    // some reason the same object
    // Take ownership of a copy of newFloozit
    Floozit * tmp = [newFloozit copy];
    // We no longer need old value of myFloozit, so we release it.
    [myFloozit release]; 
    // tmp contains a value that we own, we just need to assign
    // it to the correct name.
    myFloozit = tmp;
}

Można to nieco poprawić, sprawdzając najpierw, czy newFloozit i myFloozit są takie same, i nie robiąc nic, jeśli są.

0
jscs 30 maj 2011, 00:25