Jak zastąpić słabe odwołania podczas korzystania z ARC i kierowania na iOS 4.0?

87

Zacząłem opracowywać moją pierwszą aplikację na iOS z Xcode 4.2 i celowałem w iOS 5.0 z szablonem „aplikacji narzędziowej” (tym, który jest dostarczany z FlipsideViewController).

Czytałem, że ponieważ ARC jest funkcją czasu kompilacji, powinien być również kompatybilny z iOS 4, więc próbowałem skierować moją aplikację na 4.3 i spróbować ją skompilować. Kiedy to robię, pojawia się ten błąd:

FlipsideViewController.m: błąd: Automatyczne liczenie odwołań Problem: bieżący cel wdrożenia nie obsługuje automatycznych __ słabych odwołań

Odnosi się do tej linii:

@synthesize delegate = _delegate;

Ta zmienna jest zadeklarowana jako:

@property (weak, nonatomic) IBOutlet id <FlipsideViewControllerDelegate> delegate;

Rozumiem, że „słabe odwołania” nie są obsługiwane w iOS 4, ale nie bardzo rozumiem, dlaczego miałbym chcieć używać słabego odwołania na początku, ani nie mogę dowiedzieć się, jak przepisać rzeczy, aby uniknąć ich używania, podczas gdy nadal korzysta z ARC (w końcu ma działać z iOS 4 AND 5, prawda?)

Mason G. Zhwiti
źródło

Odpowiedzi:

149

Aby ukierunkować na starszy system operacyjny, możesz użyć unsafe_unretainedzamiast weakw deklaracji właściwości i powinno to działać w ten sam sposób. weakodwołania same się zerują, gdy ich cel odchodzi, ale unsafe_unretainedpozostawia otwartą możliwość, że obiekt, do którego tworzysz łącze, może zmienić się w wiszący wskaźnik, gdy zostanie zwolniony. To drugie zachowuje się tak samo, jak w przypadku użycia assignjako deklaracji właściwości w ręcznym zarządzaniu pamięcią.

Robisz to, aby uniknąć zachowania cykli, o których wspominam w mojej odpowiedzi tutaj . Nie chcesz mieć silnego wskaźnika do czegoś, co może mieć silny wskaźnik z powrotem do oryginalnego obiektu. Wtedy nic nie zostanie poprawnie zwolnione.

Brad Larson
źródło
Dzięki za radę. Mówisz „kierować na starszy system operacyjny…”. Czy to oznacza, że ​​powinienem używać unsafe_unretained tylko w kompilacjach aplikacji starszych niż 5.0? Czy mogę po prostu użyć unsafe_unretained w moim kodzie i skompilować go tak, aby był przeznaczony dla wersji 4.x i 5.x?
Mason G. Zhwiti
1
@Mason - unsafe_unretainedjest obsługiwany zarówno w iOS 4.x, jak i 5.0, dzięki czemu zapewnia kompatybilność wsteczną. Jeśli tworzysz tylko wersję 5.0, możesz przełączyć się na, weakaby skorzystać z dodatkowego bezpieczeństwa, które zapewnia.
Brad Larson
Próbowałem unsafe_unretained, i tak zadziałało. Jednak dostałem wiele ostrzeżeń, takich jak '"** __NSAutoreleaseNoPool (): Object 0x564bd90 klasy __NSArrayM autoreleased bez puli na miejscu - po prostu przeciekanie" * ", to normalne?
piąty
1
@fifth - To zupełnie niezwiązany problem. Uruchamiasz coś w wątku w tle bez zainstalowanej puli autowydzielania. Wątki utworzone ręcznie nie mają własnej puli autorelease, więc musisz ją utworzyć samodzielnie @autoreleasepool(w ARC, NSAutoreleasePool dla starszych implementacji z liczonymi ręcznie odwołaniami).
Brad Larson
@Brad, to pomocne, ostrzeżenia zniknęły, otrzymałem kilka wywołań performSelectorInBackground.
piąty
11

Jeśli używasz tylko słabych odwołań dla dodatkowego bezpieczeństwa, ręcznie wywołaj nowe funkcje środowiska uruchomieniowego, jeśli są dostępne, a jeśli nie, powróć do prostego przypisania __unsafe_unretainedzmiennych.

ZWRCompatibility.h nieco to uprości.

rpetrich
źródło
10

Dzięki bibliotece kompatybilności PLWeakCompatibilty Mike'a Asha , możesz teraz po prostu używać __weak również na iOS 4.x.

Jest niezwykle łatwy w konfiguracji i nie wymaga dodatkowego namysłu ani wysiłku w porównaniu z wersją 5.x.

nschum
źródło