Uczę się Swift dla iOS 8 / OSX 10.10, postępując zgodnie z tym samouczkiem , a termin „ nieopakowana wartość ” jest używany kilka razy, jak w tym akapicie (w sekcji Obiekty i klasa ):
Podczas pracy z wartościami opcjonalnymi możesz pisać? przed operacjami, takimi jak metody, właściwości i indeksy dolne. Jeśli wartość przed? jest zero, wszystko po? jest ignorowane, a wartość całego wyrażenia wynosi zero. W przeciwnym razie wartość opcjonalna jest rozpakowywana , a wszystko po znaku? działa na nieopakowanej wartości . W obu przypadkach wartość całego wyrażenia jest wartością opcjonalną.
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare?.sideLength
Nie rozumiem i bez powodzenia szukałem w internecie.
Co to znaczy?
Edytować
Z odpowiedzi Cezarego wynika niewielka różnica między wyjściem oryginalnego kodu a ostatecznym rozwiązaniem (przetestowanym na placu zabaw):
Oryginalny kod
Rozwiązanie Cezarego
Właściwości nadklasy są wyświetlane na wyjściu w drugim przypadku, podczas gdy w pierwszym przypadku jest pusty obiekt.
Czy wynik nie powinien być identyczny w obu przypadkach?
Powiązane pytania i odpowiedzi: Jaka jest wartość opcjonalna w języku Swift?
Odpowiedzi:
Najpierw musisz zrozumieć, czym jest typ opcjonalny. Opcjonalny typ zasadniczo oznacza, że zmienna może być
nil
.Przykład:
Znak zapytania wskazuje, że tak
canBeNil
jestnil
.To nie zadziała:
Aby uzyskać wartość ze zmiennej, jeśli jest opcjonalna, musisz ją rozpakować . Oznacza to po prostu umieszczenie wykrzyknika na końcu.
Twój kod powinien wyglądać następująco:
Przypis:
Możesz również zadeklarować opcje, aby automatycznie rozpakowywać, używając wykrzyknika zamiast znaku zapytania.
Przykład:
Zatem alternatywnym sposobem naprawy kodu jest:
EDYTOWAĆ:
Różnica, którą widzisz, jest dokładnie objawem tego, że wartość opcjonalna jest opakowana . Na wierzchu jest kolejna warstwa. Wersja nieopakowana pokazuje tylko prosty obiekt, ponieważ jest on, no cóż, rozpakowany.
Szybkie porównanie placu zabaw:
W pierwszym i drugim przypadku obiekt nie jest automatycznie rozpakowywany, więc widzisz dwie „warstwy” (
{{...}}
), podczas gdy w trzecim przypadku widzisz tylko jedną warstwę ({...}
), ponieważ obiekt jest automatycznie rozpakowywany.Różnica między pierwszym a dwoma drugimi przypadkami polega na tym, że w przypadku dwóch drugich wystąpi błąd w czasie wykonywania, jeśli
optionalSquare
jest ustawiona nanil
. Używając składni w pierwszym przypadku, możesz zrobić coś takiego:źródło
init()
funkcji klasy. Polecam przeczytanie rozdziałów „Podstawy” (dotyczy opcji), „Inicjalizacja” i „Opcjonalne łączenie” w książce Swift wydanej przez Apple.Istniejąca prawidłowa odpowiedź jest świetna, ale stwierdziłem, że aby w pełni to zrozumieć, potrzebowałem dobrej analogii, ponieważ jest to bardzo abstrakcyjna i dziwna koncepcja.
Pozwólcie więc, że pomogę tym innym programistom o „praworęcznych” (myślących wizualnie), podając inną perspektywę oprócz poprawnej odpowiedzi. Oto dobra analogia, która bardzo mi pomogła.
Analogia pakowania prezentów urodzinowych
Pomyśl o opcjach jak o prezentach urodzinowych, które są dostarczane w sztywnym, twardym, kolorowym opakowaniu.
Nie wiesz, czy coś jest w opakowaniu, dopóki nie rozpakujesz prezentu - może w ogóle nic nie ma w środku! Jeśli coś jest w środku, może to być kolejny prezent, który również jest zapakowany i który również może nic nie zawierać . Możesz nawet rozpakować 100 zagnieżdżonych prezentów, aby w końcu odkryć, że nie było nic poza opakowaniem .
Jeśli wartość opcjonalna nie jest
nil
, teraz odkryłeś pudełko zawierające coś . Ale zwłaszcza jeśli wartość nie jest jawnie wpisana i jest zmienną, a nie predefiniowaną stałą, może być konieczne otwarcie pola, zanim będziesz mógł dowiedzieć się czegoś konkretnego o tym, co jest w polu, np. Jaki to jest typ lub jaki jest rzeczywista wartość to.Co jest w pudełku?! Analogia
Nawet po rozpakowaniu zmiennej nadal jesteś jak Brad Pitt z ostatniej sceny w SE7EN ( ostrzeżenie : spoilery i wulgarny język i przemoc z bardzo oceną R), ponieważ nawet po rozpakowaniu prezentu jesteś w następującej sytuacji: masz teraz
nil
albo pudełko zawierające coś (ale nie wiesz co).Możesz znać typ czegoś . Na przykład, jeśli zadeklarowałeś zmienną jako typ,
[Int:Any?]
wiedziałbyś, że masz (potencjalnie pusty) słownik z indeksami całkowitymi, które dają opakowaną zawartość dowolnego starego typu.Dlatego zajmowanie się typami kolekcji (słownikami i tablicami) w języku Swift może stać się trochę owłosione.
Przykładem:
źródło
Swift kładzie duży nacisk na bezpieczeństwo typów. Cały język Swift został zaprojektowany z myślą o bezpieczeństwie. To jedna z cech charakterystycznych Swifta, którą należy powitać z otwartymi ramionami. Pomoże w opracowaniu czystego, czytelnego kodu i pomoże zapobiec awariom aplikacji.
Wszystkie opcje w Swift są oznaczone
?
symbolem. Ustawiając?
po nazwie typu, w którym deklarujesz jako opcjonalny, zasadniczo rzutujesz to nie jako typ, w którym znajduje się przed?
, ale zamiast tego jako typ opcjonalny .Korzystanie z opcjonalnego
Ten sposób nie oznacza, że użytkownik pracuje z typem
String
. Oznacza to, że pracujesz z typemString?
(ciąg opcjonalny lub opcjonalny ciąg). W rzeczywistości za każdym razem, gdy spróbujeszw czasie wykonywania wydrukuje konsola debugowania
Optional("foobar")
. Część „Optional()
” wskazuje, że ta zmienna może, ale nie musi, mieć wartość w czasie wykonywania, ale tak się składa, że obecnie zawiera ciąg „foobar”. To "Optional()
" wskazanie pozostanie, chyba że zrobisz tak zwane "" rozpakowywanie "opcjonalnej wartości.Rozpakowanie opcjonalnego oznacza, że teraz rzutujesz ten typ jako nieopcjonalny. Spowoduje to wygenerowanie nowego typu i przypisanie wartości, która znajdowała się w tym opcjonalnym, do nowego nieopcjonalnego typu. W ten sposób można wykonywać operacje na tej zmiennej, ponieważ kompilator gwarantuje, że ma ona stałą wartość.
Warunkowe rozpakowanie sprawdzi, czy wartość w opcjonalnym jest,
nil
czy nie. Jeśli tak nie jestnil
, pojawi się nowo utworzona stała zmienna, której zostanie przypisana wartość i zostanie rozpakowana do nieopcjonalnej stałej. A stamtąd możesz bezpiecznie używać nieopcjonalnego wif
bloku.Warunkowe rozpakowanie opcji jest najczystszym sposobem uzyskania dostępu do wartości opcjonalnej, ponieważ jeśli zawiera ona wartość zerową, to wszystko w bloku if let nie zostanie wykonane. Oczywiście, tak jak w przypadku każdej instrukcji if, możesz dołączyć blok else
Wymuszone rozpakowywanie odbywa się za pomocą tak zwanego
!
operatora („bang”). Jest to mniej bezpieczne, ale nadal umożliwia kompilację kodu. Jednak za każdym razem, gdy używasz operatora bang, musisz mieć 1000% pewności, że zmienna faktycznie zawiera stałą wartość, zanim zostanie wymuszona rozpakowana.Powyższy kod jest całkowicie prawidłowym kodem Swift. Wyświetla wartość,
myString
która została ustawiona jako „foobar”. Użytkownik zobaczyfoobar
wydrukowany w konsoli i to wszystko. Ale załóżmy, że wartość nigdy nie została ustawiona:Teraz mamy inną sytuację na naszych rękach. W przeciwieństwie do Objective-C, za każdym razem, gdy podejmowana jest próba wymuszonego rozpakowania opcjonalnego, a opcjonalny nie został ustawiony i jest
nil
, gdy spróbujesz rozpakować opcjonalny, aby zobaczyć, co jest w środku, aplikacja ulegnie awarii.Rozpakowywanie z rzutowaniem typów . Jak powiedzieliśmy wcześniej, chociaż jesteś
unwrapping
opcjonalnym, w rzeczywistości rzutujesz na typ nieopcjonalny, możesz również rzutować nieopcjonalny na inny typ. Na przykład:Gdzieś w naszym kodzie zmienna
something
otrzyma jakąś wartość. Może używamy leków generycznych, a może istnieje inna logika, która spowoduje zmianę tego. Więc później w naszym kodzie chcemy użyć,something
ale nadal możemy traktować go inaczej, jeśli jest to inny typ. W takim przypadku będziesz chciał użyćas
słowa kluczowego, aby to ustalić:Zwróć uwagę na różnicę między tymi dwoma
as
słowami kluczowymi. Tak jak poprzednio, gdy siłą rozpakowaliśmy element opcjonalny, używaliśmy do tego!
operatora bang. Tutaj zrobisz to samo, ale zamiast rzucać jako nieobowiązkowe, rzucasz również jakoInt
. I musi być możliwe do obniżenia, ponieważInt
w przeciwnym razie, na przykład przy użyciu operatora bang, gdy wartością jest,nil
aplikacja ulegnie awarii.Aby w ogóle użyć tych zmiennych w jakiejś operacji matematycznej, muszą zostać rozpakowane, aby to zrobić.
Na przykład w Swift tylko prawidłowe typy danych liczbowych tego samego rodzaju mogą być obsługiwane na sobie nawzajem. Kiedy rzucasz typ za pomocą
as!
, wymuszasz obniżenie tej zmiennej, tak jakbyś był pewien, że jest tego typu, dlatego bezpieczna jest operacja i nie zawieszanie aplikacji. Jest to w porządku, o ile zmienna rzeczywiście jest typu, do którego ją rzucasz, w przeciwnym razie będziesz mieć bałagan na rękach.Niemniej jednak rzutowanie za pomocą
as!
pozwoli na kompilację kodu. Casting z anas?
to inna historia. W rzeczywistościas?
deklaruje razemInt
jako zupełnie inny typ danych.Teraz jest
Optional(0)
A jeśli kiedykolwiek próbowałeś odrobić pracę domową, pisząc coś takiego
Twój nauczyciel matematyki prawdopodobnie dałby ci „F”. To samo z Swift. Tyle że Swift wolałby raczej w ogóle nie kompilować, niż wystawiać ocenę. Ponieważ pod koniec dnia opcja opcjonalna może w rzeczywistości być zerowa .
Bezpieczeństwo przede wszystkim.
źródło
'?' oznacza opcjonalne wyrażenie łańcuchowe,
„!” oznacza wartość siły
źródło