Kiedy używać -retainCount?

110

Chciałbym wiedzieć, z jakiej sytuacji korzystałeś do -retainCounttej pory, a ostatecznie jakie problemy mogą się zdarzyć przy jego użyciu.

Dzięki.

Moszi
źródło
5
powinieneś nigdy przez użytkownika -retainCount.
holex
3
(Z wyjątkiem sytuacji, kiedy powinieneś. Bardzo czasami przydatna jest pomoc w zrozumieniu, co się dzieje, o ile zdajesz sobie sprawę, że czasami może to być naprawdę mylące. I oczywiście w ogóle nie jest dozwolone, jeśli używasz ARC.)
Hot Licks

Odpowiedzi:

243

Nigdy nie powinieneś używać -retainCount, ponieważ nigdy nie mówi ci nic przydatnego. Wdrożenie frameworków Foundation i AppKit / UIKit jest nieprzejrzyste; nie wiesz, co jest zatrzymywane, dlaczego to jest zatrzymywane, kto to zachowuje, kiedy zostało zachowane i tak dalej.

Na przykład:

  • Można by pomyśleć, że [NSNumber numberWithInt:1]miałoby toretainCount 1. Nie. Jest 2.
  • Można by pomyśleć, że to @"Foo"będzie równe retainCount1. Nie. Jest to 1152921504606846975.
  • Można by pomyśleć, że to [NSString stringWithString:@"Foo"]będzie równe retainCount1. Nie. Ponownie jest to 1152921504606846975.

Zasadniczo, ponieważ wszystko może zachować obiekt (a tym samym zmienić jego retainCount), a ponieważ nie masz źródła większości kodu, który uruchamia aplikację, obiekt retainCountjest bez znaczenia.

Jeśli próbujesz wyśledzić, dlaczego obiekt nie jest zwalniany, użyj narzędzia Wycieki w Instrumentach. Jeśli próbujesz ustalić, dlaczego obiekt został zwolniony zbyt wcześnie, użyj narzędzia Zombie w Instrumentach.

Ale nie używaj -retainCount. To naprawdę bezwartościowa metoda.

edytować

Proszę, wszyscy wejdź na http://bugreport.apple.com i poproś o -retainCountwycofanie. Im więcej osób o to prosi, tym lepiej.

edytuj # 2

W ramach aktualizacji [NSNumber numberWithInt:1]ma teraz retainCountnumer 9223372036854775807. Jeśli Twój kod oczekiwał, że będzie to 2, Twój kod jest teraz uszkodzony.

Dave DeLong
źródło
4
Dzięki @ Dave-Delong za przykłady.
Moszi
1
retainCount jest obecnie przydatny dla singletonów (teraz pytanie brzmi, jak przydatne są singletony ...) - (NSUInteger)retainCount{return NSUIntegerMax;}.
Joe
8
@Joe możesz utworzyć singletona bez nadpisywania retainCount.
Dave DeLong,
5
@Joe Jestem tego świadomy; Google „goal-c singleton” dla całej dyskusji na temat tego, dlaczego ten przykład nie jest zbyt dobry.
Dave DeLong,
2
Jedną z rzeczy, których używam - @ DaveDeLong, możesz również uznać to za złe, ale nie sądzę - to nadpisanie dealloców i initów i umieszczenie w nich NSLogs (nawet z ARC). To daje mi wielką ideę, czy obiekty są coraz dealloced lub nie, co jest prawdziwe pytanie jesteśmy zazwyczaj próbuje odpowiedzieć ..
Dan Rosenstark
50

NIGDY!

Poważnie. Po prostu tego nie rób.

Wystarczy postępować zgodnie z Wytyczne zarządzanie pamięcią i tylko zwolnić co alloc, newlub copy(lub cokolwiek nazywane retainpo pierwotnie).

@bbum powiedział to najlepiej tutaj na SO , a jeszcze bardziej szczegółowo na swoim blogu .

Abizern
źródło
8
Ponieważ myślisz, że liczysz pamięć, ale będziesz to robić źle.
Abizern
@Abizern - a co z sytuacją singletona w jednej z pozostałych odpowiedzi?
Moszi
3
Aby dodać do tego, wszelkie informacje, które możesz uzyskać, -retainCountmożna uzyskać (o wiele bardziej szczegółowo) z Instruments i jego narzędzi.
Dave DeLong
3
Aby dodać do tego, co powiedział Dave; bezwzględna liczba zachowań obiektu jest szczegółem implementacji. Zarówno szczegół wewnętrznych elementów obiektu, jak i / lub szczegół dowolnego innego obiektu, przez który obiekt mógł przejść. Wywołanie retain, retain, retain, autorelease, autorelease, autoreleasemoże być całkowicie poprawny wynik przekazywania obiektu przez API UIKit, na przykład.
bbum
2
@ d11wtq Jeśli retainCount ever == 0, osobliwość została osiągnięta!
bbum
14

Obiekty zwolnione automatycznie są jednym z przypadków, w których sprawdzenie -retainCount jest nieinformacyjne i może wprowadzać w błąd. Licznik retainy nie mówi nic o tym, ile razy -autorelease zostało wywołanych na obiekcie, a zatem ile razy zostanie on zwolniony, gdy bieżąca pula autowydzielania zostanie wyczerpana.

Jonasza
źródło
1
Dzięki - to dobra uwaga. To jest pierwsza odpowiedź, która ma opisany powód, dlaczego nie używać retainCount, oprócz ogólnego „nie rób”.
Moszi
1
@Moszi: Twoje pytanie brzmiało: „Kiedy używać retainCount?” - jeśli nie chciałeś zadać tego pytania, powinieneś zadać coś innego.
Chuck,
@chuck - właściwie interesowało mnie „kiedy go używać”, jednak wydaje się, że każda odpowiedź brzmi „nigdy”… Ale - myślę, że masz rację. Zostawię to pytanie otwarte na kilka dni i jeśli nie będzie innej odpowiedzi, to nigdy, wtedy zaakceptuję „nigdy” jako odpowiedź.
Moszi
10

Uważam , że retainCounts jest bardzo przydatne podczas sprawdzania za pomocą „Instrumentów”.

Korzystając z narzędzia „alokacje”, upewnij się, że opcja „Rekord liczników odwołań” jest włączona i możesz przejść do dowolnego obiektu i zobaczyć jego historię retainCount.

Łącząc alokacje i wydania, możesz uzyskać dobry obraz tego, co się dzieje i często rozwiązywać trudne przypadki, w których coś nie jest publikowane.

To nigdy mnie nie zawiodło - w tym znajdowanie błędów we wczesnych wersjach beta iOS.

Egil
źródło
5

Spójrz na dokumentację Apple na temat NSObject, prawie obejmuje ona twoje pytanie: NSObject retainCount

Krótko mówiąc, retainCount jest prawdopodobnie bezużyteczne, chyba że zaimplementowałeś własny system liczenia referencji (i mogę prawie zagwarantować, że nie będziesz go mieć).

Według własnych słów Apple, retainCount „zwykle nie ma wartości w debugowaniu problemów z zarządzaniem pamięcią”.

lxt
źródło
Przede wszystkim dziękuję za odpowiedź. Zwykle reakcja ludzi na to pytanie brzmi „NIGDY”. (Zobacz odpowiedzi). Właściwie „brak wartości w debugowaniu” nie oznacza „NIGDY”. Tak więc moje pytanie brzmi - dlaczego silne poczucie, że go nie używam (np. W implementacji singletona - znowu jedna z odpowiedzi)?
Moszi
Myślę, że musiałbyś podać więcej informacji o tym, do czego go używasz. Dopuszczalnym zastosowaniem byłoby, zgodnie z sugestią Apple, zastąpienie retainCount w celu zaimplementowania własnego systemu liczenia referencji. Ale w praktyce nigdy byś tego nie zobaczył (ja nigdy nie widziałem). Silna reakcja generalnie wynika z faktu, że Apple zalecało pozostawienie retainCount w spokoju (w swoich grupach pocztowych, dokumentacji, forach programistów itp.).
lxt
1
@Moszi: Debugowanie to jedyna sytuacja, w której większość ludzi może sobie wyobrazić, że ma wartość, więc jeśli jest tam zawodna, nigdy nie jest przydatna. Jakie inne zastosowania myślisz?
Chuck,
4

Oczywiście nigdy nie powinieneś używać metody retainCount w swoim kodzie, ponieważ znaczenie jej wartości zależy od tego, ile autowydzierżawień zostało zastosowanych do obiektu, a tego nie możesz przewidzieć. Jest to jednak bardzo przydatne do debugowania - szczególnie podczas wyszukiwania wycieków pamięci w kodzie, który wywołuje metody obiektów Appkit poza główną pętlą zdarzeń - i nie powinno być przestarzałe.

Starając się przedstawić swój punkt widzenia, poważnie przeceniliście niezbadany charakter wartości. Prawdą jest, że nie zawsze jest to liczba referencyjna. Istnieją pewne specjalne wartości używane dla flag, na przykład w celu wskazania, że ​​obiekt nie powinien być nigdy zwalniany. Liczba taka jak 1152921504606846975 wygląda bardzo tajemniczo, dopóki nie napiszesz jej szesnastkowo i nie otrzymasz 0xfffffffffffffff. A 9223372036854775807 to 0x7fffffffffffffff w zapisie szesnastkowym. I naprawdę nie jest tak zaskakujące, że ktoś zdecydowałby się użyć takich wartości jako flag, biorąc pod uwagę, że uzyskanie wartości retainCount równej większej liczbie zajęłoby prawie 3000 lat, zakładając, że wartość retainCount wzrosłaby 100 000 000 razy na sekundę.

Marc Culler
źródło
3

Jakie problemy możesz napotkać stosując go? Wszystko, co robi, to zwraca liczbę zachowań obiektu. Nigdy do tego nie dzwoniłem i nie mogę wymyślić żadnego powodu, dla którego bym to zrobił. Zastąpiłem to w singletonach, aby upewnić się, że nie są one jednak cofnięte.

ughoavgfhw
źródło
2
Nie ma powodu, aby go przesłonić w przypadku singletona. W Foundation / CoreFoundation nie ma ścieżek kodu, które są używane retainCountdo zarządzania pamięcią.
bbum
Czy release nie używa go do decydowania, czy powinien wywołać dealloc?
ughoavgfhw
2
Nie; wewnętrzna implementacja retain / release / autorelease ma głębokie korzenie w CoreFoundation i naprawdę nie jest tym, czego można by się spodziewać. Idź do źródła CoreFoundation (jest dostępne) i zobacz.
bbum
3

Nie powinieneś martwić się wyciekiem pamięci, dopóki aplikacja nie będzie działać i nie zrobi czegoś pożytecznego.

Gdy to nastąpi, uruchom Instruments i użyj aplikacji, aby sprawdzić, czy wycieki pamięci naprawdę się zdarzają. W większości przypadków sam stworzyłeś obiekt (a więc jesteś jego właścicielem) i zapomniałeś go zwolnić po zakończeniu.

Nie próbuj optymalizować kodu podczas jego pisania, Twoje przypuszczenia, co może spowodować wyciek pamięci lub co może zająć zbyt dużo czasu, są często błędne, gdy faktycznie używasz aplikacji normalnie.

Spróbuj napisać poprawny kod, np. Jeśli tworzysz obiekt za pomocą alokacji i tym podobnych, upewnij się, że wydałeś go poprawnie.

ExitToShell
źródło
0

Nigdy nie powinieneś używać go w swoim kodzie, ale zdecydowanie może pomóc podczas debugowania

iosdevnyc
źródło
0

Nigdy nie używaj -retainCount w swoim kodzie. Jednak jeśli użyjesz, nigdy nie zobaczysz, że zwraca zero. Zastanów się, dlaczego. :-)

hrchen
źródło
0

Przykłady użyte w poście Dave'a to NSNumber i NSStrings ... więc jeśli używasz innych klas, takich jak UIViews, jestem pewien, że otrzymasz poprawną odpowiedź (liczba zatrzymań zależy od implementacji i jest przewidywalna).

Peng
źródło