2011-02-10 8 views
5

"Potencjalny wyciek obiektu przydzielonego w linii n i zapisany w zmiennej" zmienna "."W jaki sposób można wyłączyć ostrzeżenie o statycznym analizatorze Xcode Clang?

Zwykle jest to bardzo pomocne ostrzeżenie analizator, ale istnieje kilka sytuacji, w których mogę zrobić irytujące fałszywych alarmów, które chciałbym, aby stłumić, aby moje wyniki analizatora czyste. W obronie analizatora, to, co dostrzega, z pewnością byłoby wyciekiem pamięci, gdyby nie uwolnienie na innej ścieżce wykonania (do której jest ślepa).

Zajmę się moją sytuacją. Zdarza się to w różnych smakach, ale ogólny wzór jest następujący:

  1. Obiekt zostaje przydzielony, a jego uczestnik jest ustawiony.
  2. Coś jest zrobione z obiektem. (Zadanie rozpoczęte, wyświetlany widok, itp.).
  3. Zakończono wykonywanie bieżącej metody. (Wprowadź ostrzeżenie o Clang).
  4. Obiekt decyduje, że jego zadanie zostało zakończone, wysyła delegata wiadomość.
  5. Delegat zwalnia obiekt.

To wcale nie jest ezoteryczny wzór, więc mam nadzieję, że tłumienie jest możliwe. Wiem, że można tego uniknąć, przechowując obrażliwy obiekt w ivar, który jest później zwolniony, ale bardzo wolę nie dodawać zanieczyszczenia ivar.

+0

Uderza mnie tak dziwnie, że delegat obiektu go zatrzymuje. Zazwyczaj obiekt zachowuje delegata, a delegat zatrzyma obiekt w cyklu zatrzymania. Nie mówię, że są przypadki ZERO, w których delegat może chcieć zatrzymać (być może krótkotrwały) obiekt, ale wydaje się istotne, aby wiedzieć, dlaczego tak jest w tym przypadku. Z tego, co tu powiedziano, powiedziałbym, że jest bardziej koszerny, aby obiekt zachował się przez cały czas trwania operacji i późniejszego przekazania wiadomości, niż delegatowi, aby "przejąć na własność" domniemane zachowanie przydziału/init. – ipmcc

+0

@ipmcc: Chociaż obiekt może zachować swojego delegata, a jest kilka miejsc w SDK, gdzie klasa to robi, powiedziałbym, że częstszym jest przechowywanie delegata jako słabego odniesienia, aby uniknąć zachowaj cykl, o którym wspomniałeś. Tak czy inaczej, zdecydowanie nie jest "typowy" dla obiektu, aby zachować swojego delegata. W moim przypadku, pewna klasa utworzyła obiekt z alloc/init i ustawiła się jako delegat. Jako właściciel klasy delegat później zwalnia obiekt po jego zakończeniu. Nie ma tu wymyślonego prawa własności. –

+0

@ipmcc - Matt ma rację, normalny wzór to: Obiekt A tworzy Obiekt B i ustawia się jako delegat Obiektu B. Obiekt A zachowuje Obiekt B. Kiedy Obiekt A zostanie zwolniony, upewnia się, że oddzielił się jako delegat Obiektu B, w przeciwnym razie możesz ulec awarii. – DougW

Odpowiedz

6

Clang ma kilka nowych Source Annotations. W szczególności możesz być zainteresowany atrybutem ns_consumed.

+0

Wygląda na to, czego szukam, jednak atrybut attribute_ns_consumed nie wydaje się być dostępny: __has_feature (attribute_ns_consumed) zwraca false. Dokumentacja, którą witryna konkretnie nazywa je, Adnotacje API Mac OS X. Czy są one niedostępne w systemie iOS? –

+0

Nazewnictwo jest trochę mylące, w rzeczywistości oznacza Adnotacje API kakao. A 'ns_consumed' jest raczej nowy. Nie sądzę, że ma je Clang 1.6 (wersja dostarczana z Xcode 3.2), ale mam nadzieję, że Clang 2.0 (nie testowałem). –

+0

Cóż, używam wersji 2.0 i nie ma kości. Niefortunne ... –

1

Myślę, że powinieneś posłuchać w tym przypadku komunikatu statycznego analizatora. Twój wzór ma potencjalne problemy.

W szczególności, po powrocie z metody wywołanej do wykonania kroku 5, znajdujesz się w metodzie obiektu, który mógł już zostać zwolniony. I interpretować coś wzór takiego:

// steps 1, 2, 3 
-(void) methodThatCreatesObject 
{ 
    id theObj = [[TheObj alloc] init]; 
    [theObj setDelegate: delegateObj]; 
    // other stuff 
} 

Uwaga Powyższe narusza memory management rules

// step 4 - a method of theObj 
-(void) someMethod 
{ 
    [delegate notifyTaskCompleteFromObj: self]; 
    // self points to an invalid object here. Doing anything with self results in EXC_BAD_ACCESS 
} 

Powyższe naruszy założenie określone w zasadach zarządzania pamięcią:

Odebrany obiekt jest normalnie gwarantowana ważność w ramach metody, w której została otrzymana:

jeśli powiemy, że self jest odebranym obiektem, który jest technicznie, ponieważ jest przekazywany jako parametr na stosie.

// step 5 the delegate method defined in the delegate object 

-(void) notifyTaskCompleteFromObj: (TheObj*) anObj 
{ 
    // do stuff 
    [anObj release]; 
} 

Powyższe łamie również zasady zarządzania pamięcią.

Normalny wzór to posiadanie kontrolera, który jest właścicielem zarówno delegata, jak i obiektu, który ma delegata (często kontroler sam jest delegatem). Myślę, że powinieneś przejść do tego schematu.

+0

Jeśli to był mój wzór, zgodziłbym się z tobą. Przypuszczam, że moje uogólnienie pozostawia zbyt wiele miejsca na interpretację. Oto dokładny przykład tego, co się dzieje: W metodzie obiektu kontrolera przydzielany jest inny obiekt (niestandardowe żądanie sieciowe), a jego delegat jest ustawiony na własny, a nie na inny obiekt. Zatem kontroler jest właścicielem obiektu, do którego działa jako delegat. Później, po otrzymaniu powiadomienia z żądania sieci, kontroler zwalnia żądanie. Nie ma żadnego naruszenia; Nie oddaję odpowiedzialności za inny obiekt. –

+0

@Matt: Czy mówisz, że 'theObj' w moim przykładzie jest zmienną instancji? – JeremyP

+0

Nie, nie jest.Mogę zachować odniesienie do niego jako ivar, aby wydać go później, ale ponieważ theObj przekazuje odwołanie do siebie w wiadomości delegata, wybieram zwolnienie referencji przekazanej jako parametr wiadomości, zamiast dodawać ivar do wydania to. Brak odniesienia do Obj jest dokładnie tym, czego analizator nie lubi. –

0

Przyszła mi kolejna interesująca opcja. OP podał następujący scenariusz:

  1. Obiekt zostaje przydzielony, a jego uczestnik jest ustawiony.
  2. Coś jest zrobione z obiektem. (Zadanie rozpoczęte, wyświetlany widok, itp.).
  3. Zakończono wykonywanie bieżącej metody. (Wprowadź ostrzeżenie o Clang).
  4. Obiekt decyduje, że jego zadanie zostało zakończone, wysyła delegata wiadomość.
  5. Delegat zwalnia obiekt.

Jeżeli zamiast wyraźnego zwolnienia, to po prostu chciał przedłużyć żywotność przydzielonego obiektu do obiektu Alokacja/delegeate, można do tego:

TheObject* foo = [[TheObject alloc] init] autorelease]; 
foo.delegate = self; 
[foo doSomething]; 
objc_setAssociatedObject(self, foo, foo, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
return; 

Ustawiając foo jako powiązany obiekt z polityką zachowania, osoba delegowana (self) skutecznie zachowuje obiekt, który zostanie następnie zwolniony za każdym razem, gdy delegat (self) zostanie zwolniony (później).

To nie jest DOKŁADNIE to, o co poprosił PO, ale jest to jednak przydatny wzór i wydaje się, że prawdopodobnie wystarczyłoby w sytuacji, którą przedstawił PO.

Powiązane problemy