2009-09-03 22 views

Odpowiedz

26

Szerokie zastosowanie NSAssert() nie zamieni ObjC w Eiffel, ale nadal jest to dość dobra praktyka, o ile pamiętasz, jak to faktycznie jest realizowane i co robi. O czym należy pamiętać: NSAssert():

Xcode nie wyłącza domyślnie NSAssert() w trybie zwolnienia. Musisz pamiętać, aby dodać NS_BLOCK_ASSERTIONS do GCC_PREPROCESSOR_DEFINITIONS w tobie xcconfig. (Jesteś using xcconfigs, prawda?) Powszechnym problemem jest twierdzenie, że liczba zerowa jest zerowa w przypadkach, gdy zero będzie działać cicho; może to oznaczać awarie w terenie dla rzeczy, które mogły zostać odzyskane z wdziękiem. Nie jest to związane z makrem NDEBUG używanym przez assert() i musisz pamiętać, aby zdefiniować oba, jeśli twój kod zawiera oba typy asercji.

Jeśli skompilujesz NSAssert() w trybie zwolnienia, nie otrzymasz żadnego wskazania, gdzie wystąpił problem, gdy klienci wysyłają Ci swoje dzienniki. Osobiście zawijam NSAssert() w moich własnych makrach, które zawsze logują się, nawet w trybie Release.

często wymusza zduplikowaną logikę. Rozważmy przypadek testowania wskaźnika C++ dla NULL. Używasz NSAssert(), ale musisz nadal trzeba również użyć prostego testu if(), aby uniknąć awarii w terenie. Ten rodzaj duplikowanego kodu może stać się źródłem błędów i widziałem kod, który nie działa z powodu twierdzeń, które nie są już poprawne. (Na szczęście generalnie jest to tryb debugowania!) Dużo debatowałem nad tworzeniem makra, które łączyłoby twierdzenie z if(), ale trudno to zrobić bez bycia wrażliwym lub utrudniającym zrozumienie kodu.

Ze względu na ostatni numer zazwyczaj umieszczam "NSAssert(NO, ...)" w klauzuli else{} zamiast wykonywania asercji u góry metody. To nie jest idealne, ponieważ odsuwa kontrakt od podpisu metody (zmniejszając w ten sposób jego korzyść z dokumentu), ale jest to najskuteczniejsze podejście, jakie znalazłem w praktyce.

+0

Nie widzę powodu, aby skończyć z duplikatem kodu. Jeśli asercja nie powiedzie się, twój kod nie ma obowiązku zachowania się z awarii. W rzeczywistości nie ma sensu, ponieważ założenie, które wprowadziłeś zostało złamane, więc nie ma rozsądnego sposobu, aby zapisać program z późniejszej awarii, ze względu na niespójny stan. –

+0

Twój kod zawsze ma obowiązek zachowywać się dobrze dla użytkownika. Podczas gdy w niektórych przypadkach obawa o uszkodzenie danych oznacza, że ​​natychmiastowe zawieszenie jest jedynym podejściem. Ale w wielu przypadkach nie jest to prawdą i odzyskiwanie, pokazując błąd, a nawet nie robiąc nic, jest lepsze w wersji Release przeciwko awarii i pozostawieniu użytkownika wpatrującego się w Springboard bez żadnych informacji. Widziałem wystarczająco dużo niepoprawnych twierdzeń w kodzie produkcyjnym, aby uważać na zapobiegawcze awarie w wersji Release w przypadku braku możliwości uszkodzenia danych. Debugowanie jest zupełnie inną sytuacją i zalecam szybkie zderzenie. –

+0

Dobra aplikacja potwierdza, że ​​ma błędy i chce je powstrzymać. To, że mam drobny błąd w systemie pomocy, nie powinno oznaczać, że cała gra powinna się zawiesić, ponieważ technicznie "program jest teraz niezdefiniowany". Każdy prawdziwy program każdej wielkości wiąże się z wieloma nieokreślonymi zachowaniami. Naszym obowiązkiem jest minimalizowanie tego, ale także życie w nim i niepowodzenie za każdym razem, gdy coś wygląda dziwnie. –

7

Debugowanie. Kiedy piszemy kod, prawie zawsze przyjmujecie założenia. Założenia dotyczące stanu środowiska, wartości twoich parametrów, twoich lokalnych zmiennych i pól, itp. Często te założenia są po prostu złe (stary kolega dał mi dobrą maksymę, że "Wniebowzięcie jest matką wszystkich fsckups") .

Istnieje szereg twierdzeń potwierdzających twoje założenia w miejscu, w którym je popełniłeś. Masz pewną znaną i udokumentowaną metodę, która działa tylko dla x> 5? Zapewnij to!

Asercje żyją obok testów jednostkowych i metod formalnych w ramach dobrej praktyki kodowania. Podczas gdy niektórzy mogą pomyśleć o wszechstronnych testach jednostkowych, zapewnienie asercji jest zbędne, tak nie jest. Na przykład możesz mieć założenie metody, która, powiedzmy, pracownicy mają zawsze powyżej 16 lat i poniżej 100 lat - ale ten kod w tej chwili tego nie wymaga. Testy jednostkowe, które pomyślnie przejdą te parametry, zakończą się sukcesem, ale później, gdy będziesz potrzebować użyć założenia, będziesz mieć kod wszędzie, gdzie minął test, ale jest błędny.

9

Najważniejszym ostrzeżeniem są skutki uboczne.Jeśli piszesz:

NSAssert([self.navigationController popViewControllerAnimated:YES]!=nil,@"Something fails"); 

popViewControllerAnimated: zostanie wykonany w wersji debugowania, ale nie w tej wersji systemu, które stykowych NSAssert(). Oznacza to, że twoja wersja wydania będzie działać inaczej niż wersja debugowania.

Problem ten znika, jeśli jesteś ostrożny, wystarczy:

UIViewController* vc = [self.navigationController popViewControllerAnimated:YES]; 
NSAssert(vc!=nil,@"Something fails"); 
+0

+1 wnikliwy, chociaż nigdy nie wzywam metod w asserts. –

Powiązane problemy