Wraz z Xcode 6.3 wprowadzono nowe adnotacje, aby lepiej wyrazić zamiar API w Objective-C (i oczywiście w celu zapewnienia lepszej obsługi Swift). Adnotacje te były oczywiście nonnull
, nullable
i null_unspecified
.
Ale w przypadku Xcode 7 pojawia się wiele ostrzeżeń, takich jak:
We wskaźniku brakuje specyfikatora typu dopuszczalności wartości null (_Nonnull, _Nullable lub _Null_unspecified).
Oprócz tego Apple używa innego typu specyfikatorów wartości null, oznaczając ich kod C ( źródło ):
CFArrayRef __nonnull CFArrayCreate(
CFAllocatorRef __nullable allocator, const void * __nonnull * __nullable values, CFIndex numValues, const CFArrayCallBacks * __nullable callBacks);
Podsumowując, mamy teraz te 3 różne adnotacje dopuszczalności wartości zerowej:
nonnull
,nullable
,null_unspecified
_Nonnull
,_Nullable
,_Null_unspecified
__nonnull
,__nullable
,__null_unspecified
Mimo że wiem, dlaczego i gdzie użyć której adnotacji, trochę się pogubiłem, jakiego typu adnotacje mam użyć, gdzie i dlaczego. Oto, co mogłem zebrać:
- Dla właściwości należy używać
nonnull
,nullable
,null_unspecified
. - Dla parametrów metody należy używać
nonnull
,nullable
,null_unspecified
. - Dla metod C powinno się używać
__nonnull
,__nullable
,__null_unspecified
. - W innych przypadkach, takich jak podwójne wskaźniki należy używać
_Nonnull
,_Nullable
,_Null_unspecified
.
Ale wciąż nie wiem, dlaczego mamy tak wiele adnotacji, które zasadniczo robią to samo.
Więc moje pytanie brzmi:
Jaka jest dokładna różnica między tymi adnotacjami, jak je poprawnie umieścić i dlaczego?
źródło
Odpowiedzi:
Z
clang
dokumentacji :, i
Tak więc dla zwracanych metod i parametrów możesz użyć wersji z podwójnym podkreśleniem
__nonnull
/__nullable
/__null_unspecified
zamiast albo z pojedynczym podkreśleniem, albo zamiast wersji bez podkreślenia. Różnica polega na tym, że pojedyncze i podwójne podkreślone muszą być umieszczone po definicji typu, a niewidoczne przed definicją typu.Zatem poniższe deklaracje są równoważne i poprawne:
Parametry:
W przypadku nieruchomości:
Sytuacja komplikuje się jednak, gdy w grę wchodzą podwójne wskaźniki lub bloki zwracające coś innego niż void, ponieważ te bez podkreślenia nie są tutaj dozwolone:
Podobnie jak w przypadku metod, które akceptują bloki jako parametry, należy pamiętać, że kwalifikator
nonnull
/nullable
odnosi się do bloku, a nie do jego zwracanego typu, dlatego poniższe są równoważne:Jeśli blok ma wartość zwracaną, jesteś zmuszony do jednej z wersji z podkreśleniem:
Podsumowując, możesz użyć jednego z nich, o ile kompilator może określić element, do którego ma przypisać kwalifikator.
źródło
_Null_unspecified
w Swift przekłada się to na opcjonalne? nieobowiązkowe czy co?Z bloga Swift :
źródło
Bardzo podobał mi się ten artykuł , więc pokazuję tylko, co napisał autor: https://swiftunboxed.com/interop/objc-nullability-annotations/
null_unspecified:
mosty do języka Swift niejawnie nieopakowanego opcjonalnego. To jest ustawienie domyślne .nonnull
: wartość nie będzie zerowa; łączy się ze zwykłym odniesieniem.nullable
: wartość może wynosić zero; mosty do opcjonalnego.null_resettable
: wartość nigdy nie może być zerowa podczas odczytu, ale można ustawić ją na zero, aby ją zresetować. Dotyczy tylko właściwości.Powyższe notacje różnią się wtedy, czy używasz ich w kontekście właściwości czy funkcji / zmiennych:
Autor artykułu podał również fajny przykład:
źródło
Jest to bardzo przydatne
i zamykanie za pomocą
Spowoduje to zniweczenie potrzeby kodu na poziomie „nullibis” :-), ponieważ w pewnym sensie sensowne jest założenie, że wszystko jest inne niż null (lub
nonnull
lub_nonnull
lub__nonnull
), chyba że zaznaczono inaczej.Niestety są też wyjątki od tej reguły ...
typedef
nie zakłada się, że są__nonnull
(uwaga,nonnull
nie wydaje się działać, trzeba użyć brzydkiego przyrodniego brata)id *
potrzebuje wyraźnego nullibi, ale wow podatek od grzechu (_Nullable id * _Nonnull
<- zgadnij, co to znaczy ...)NSError **
jest zawsze uznawana za dopuszczalnąWięc z wyjątkami od wyjątków i niespójnymi słowami kluczowymi wywołującymi tę samą funkcjonalność, być może podejście polega na użyciu brzydkich wersji
__nonnull
/__nullable
/__null_unspecified
i zamianie, gdy osoba zgodna narzeka ...? Może dlatego istnieją w nagłówkach Apple?Co ciekawe, coś umieściło to w moim kodzie ... Brzydzę się podkreśleniami w kodzie (facet ze starej szkoły Apple C ++), więc jestem absolutnie pewien, że ich nie wpisałem, ale pojawiły się (jeden przykład z kilku):
Co ciekawsze, gdzie wstawiono __nullable jest błędne ... (eek @!)
Naprawdę chciałbym móc po prostu użyć wersji bez podkreślenia, ale najwyraźniej nie działa to z kompilatorem, ponieważ jest to oznaczone jako błąd:
źródło