Jaka jest opcjonalna wartość w Swift?

267

Z dokumentacji Apple :

Możesz używać ifi letrazem do pracy z wartościami, których może brakować. Wartości te są przedstawiane jako opcje. Opcjonalna wartość zawiera wartość lub zawiera, nilaby wskazać brak wartości. Napisz znak zapytania (? ) po typie wartości, aby oznaczyć wartość jako opcjonalną.

Dlaczego chcesz użyć wartości opcjonalnej?

Tim Vermeulen
źródło
1
Opcjonalny może być również postrzegany jako implementacja monady Option / Może . Ten blog tutaj robi dobrą robotę, próbując wyjaśnić, co w przeciwnym razie jest trudną koncepcją.
StuartLC
tldr: „Swift musi jasno określić, kiedy można pominąć wartość i kiedy istnieje gwarancja, że ​​istnieje”. od doskonałej odpowiedzi
jonatan

Odpowiedzi:

531

Opcjonalny w Swift to typ, który może przechowywać wartość lub nie zawierać żadnej wartości. Opcjonalne są zapisywane przez dodanie ?do dowolnego typu:

var name: String? = "Bertie"

Opcjonalne (wraz z Generics) są jedną z najtrudniejszych do zrozumienia koncepcji Swift. Ze względu na sposób, w jaki są pisane i używane, łatwo jest źle zrozumieć, jakie są. Porównaj opcjonalne powyżej z tworzeniem normalnego ciągu:

var name: String = "Bertie" // No "?" after String

Ze składni wygląda na to, że opcjonalny ciąg znaków jest bardzo podobny do zwykłego ciągu znaków. To nie jest. Opcjonalny ciąg nie jest ciągiem z włączonymi niektórymi ustawieniami „opcjonalnymi”. To nie jest specjalna odmiana Sznurka. Ciąg i opcjonalny ciąg to zupełnie różne typy.

Oto najważniejsza rzecz, którą należy wiedzieć: Opcjonalnie jest rodzajem pojemnika. Opcjonalny ciąg to kontener, który może zawierać ciąg. Opcjonalny Int to kontener, który może zawierać Int. Pomyśl o opcjonalnym jako paczce. Zanim go otworzysz (lub „rozpakujesz” w języku opcjonalnym) nie będziesz wiedział, czy zawiera on coś, czy nic.

Możesz zobaczyć, w jaki sposób opcje są implementowane w Swift Standard Library, wpisując „Opcjonalne” w dowolnym pliku Swift i klikając go ⌘. Oto ważna część definicji:

enum Optional<Wrapped> {
    case none
    case some(Wrapped)
}

Opcjonalne jest tylko enumjedno z dwóch przypadków: .nonelub .some. Jeśli tak .some, istnieje powiązana wartość, która w powyższym przykładzie byłaby String„Cześć”. Opcjonalne używa Rodzajowych, aby nadać typ powiązanej wartości. Typ opcjonalnego ciągu nie jest String, jest Optional, a dokładniejOptional<String> .

Wszystko, co Swift robi z opcjami, to magia, dzięki której czytanie i pisanie kodu jest płynniejsze. Niestety przesłania to sposób, w jaki faktycznie działa. Później przejdę przez niektóre sztuczki.

Uwaga: Będę dużo mówił o zmiennych opcjonalnych, ale dobrze jest również tworzyć opcjonalne stałe. Zaznaczam wszystkie zmienne ich typem, aby ułatwić zrozumienie tworzonych typów typów, ale nie musisz tego robić we własnym kodzie.


Jak tworzyć opcje

Aby utworzyć opcjonalny, dodaj ?po typ, który chcesz zawinąć. Każdy typ może być opcjonalny, nawet własne typy niestandardowe. Nie możesz mieć spacji między typem a ?.

var name: String? = "Bob" // Create an optional String that contains "Bob"
var peter: Person? = Person() // An optional "Person" (custom type)

// A class with a String and an optional String property
class Car {
var modelName: String // must exist
var internalName: String? // may or may not exist
}

Korzystanie z opcji

Możesz porównać opcjonalny, nilaby sprawdzić, czy ma wartość:

var name: String? = "Bob"
name = nil // Set name to nil, the absence of a value
if name != nil {
    print("There is a name")
}
if name == nil { // Could also use an "else"
    print("Name has no value")
}

To jest trochę mylące. Oznacza to, że opcjonalne to jedno lub drugie. To albo zero, albo „Bob”. To nie jest prawda, opcja nie przekształca się w coś innego. Porównywanie go do zera jest sztuczką, aby uczynić kod łatwiejszym do odczytania. Jeśli opcja jest równa zero, oznacza to po prostu, że wyliczenie jest obecnie ustawione na .none.


Tylko opcje mogą być zerowe

Jeśli spróbujesz ustawić nie opcjonalną zmienną na zero, pojawi się błąd.

var red: String = "Red"
red = nil // error: nil cannot be assigned to type 'String'

Innym sposobem patrzenia na opcje jest uzupełnienie normalnych zmiennych Swift. Są odpowiednikiem zmiennej, która ma gwarantowaną wartość. Swift to ostrożny język, który nie znosi dwuznaczności. Większość zmiennych jest definiowanych jako nieopcjonalne, ale czasami nie jest to możliwe. Na przykład wyobraź sobie kontroler widoku, który ładuje obraz z pamięci podręcznej lub z sieci. Może lub nie może mieć tego obrazu w momencie tworzenia kontrolera widoku. Nie ma sposobu, aby zagwarantować wartość zmiennej obrazu. W takim przypadku należy ustawić opcję opcjonalną. Zaczyna się, nilgdy obraz jest pobierany, opcjonalnie pobiera wartość.

Użycie opcjonalnego ujawnia zamiary programistów. W porównaniu do Celu C, w którym dowolny obiekt może być zerowy, Swift wymaga jasnego określenia, kiedy może brakować wartości i kiedy istnieje gwarancja jej istnienia.


Aby użyć opcjonalnego, „rozpakuj” go

Opcjonalnego Stringnie można użyć zamiast faktycznego String. Aby użyć zawiniętej wartości wewnątrz opcjonalnej, musisz ją rozpakować. Najprostszym sposobem na rozpakowanie opcjonalnego jest dodanie !po opcjonalnej nazwie. Nazywa się to „wymuszaniem rozpakowywania”. Zwraca wartość wewnątrz opcjonalnego (jako pierwotnego typu), ale jeśli opcjonalny jest nil, powoduje awarię środowiska wykonawczego. Przed rozpakowaniem należy upewnić się, że istnieje wartość.

var name: String? = "Bob"
let unwrappedName: String = name!
print("Unwrapped name: \(unwrappedName)")

name = nil
let nilName: String = name! // Runtime crash. Unexpected nil.

Sprawdzanie i korzystanie z opcjonalnego

Ponieważ zawsze należy sprawdzić zero przed rozpakowaniem i użyciem opcjonalnego, jest to powszechny wzorzec:

var mealPreference: String? = "Vegetarian"
if mealPreference != nil {
    let unwrappedMealPreference: String = mealPreference!
    print("Meal: \(unwrappedMealPreference)") // or do something useful
}

W tym wzorze sprawdzasz, czy wartość jest obecna, a następnie, gdy jesteś pewien, że tak jest, wymuszasz rozpakowanie jej do tymczasowej stałej do użycia. Ponieważ jest to tak powszechne, Swift oferuje skrót za pomocą „jeśli pozwala”. Nazywa się to „opcjonalnym wiązaniem”.

var mealPreference: String? = "Vegetarian"
if let unwrappedMealPreference: String = mealPreference {
    print("Meal: \(unwrappedMealPreference)") 
}

Tworzy to tymczasową stałą (lub zmienną, jeśli zastąpisz letvar), której zakres znajduje się tylko w nawiasach if. Ponieważ używanie nazwy takiej jak „unwrappedMealPreference” lub „realMealPreference” jest dużym obciążeniem, Swift pozwala na ponowne użycie oryginalnej nazwy zmiennej, tworząc tymczasową w zakresie nawiasów

var mealPreference: String? = "Vegetarian"
if let mealPreference: String = mealPreference {
    print("Meal: \(mealPreference)") // separate from the other mealPreference
}

Oto kod pokazujący, że używana jest inna zmienna:

var mealPreference: String? = "Vegetarian"
if var mealPreference: String = mealPreference {
    print("Meal: \(mealPreference)") // mealPreference is a String, not a String?
    mealPreference = "Beef" // No effect on original
}
// This is the original mealPreference
print("Meal: \(mealPreference)") // Prints "Meal: Optional("Vegetarian")"

Opcjonalne wiązanie działa poprzez sprawdzenie, czy opcjonalne jest równe zero. Jeśli nie, rozpakowuje opcjonalne do podanej stałej i wykonuje blok. W Xcode 8.3 i późniejszych (Swift 3.1) próba wydrukowania takiej opcji opcjonalnej spowoduje bezużyteczne ostrzeżenie. Użyj opcji opcjonalnych, debugDescriptionaby go wyciszyć:

print("\(mealPreference.debugDescription)")

Do czego służą opcje?

Opcjonalne mają dwa przypadki użycia:

  1. Rzeczy, które mogą zawieść (oczekiwałem czegoś, ale nic nie dostałem)
  2. Rzeczy, które są niczym, ale mogą być czymś później (i odwrotnie)

Niektóre konkretne przykłady:

  • Właściwość, która może być tam lub nie, jak middleNamelub spousewPerson klasie
  • Metoda, która może zwrócić wartość lub nic, na przykład wyszukiwanie dopasowania w tablicy
  • Metoda, która może zwrócić wynik lub otrzymać błąd i nic nie zwrócić, na przykład próbę odczytania zawartości pliku (która zwykle zwraca dane pliku), ale plik nie istnieje
  • Deleguj właściwości, które nie zawsze muszą być ustawiane i generalnie są ustawiane po inicjalizacji
  • Dla weakwłaściwości w klasach. To, na co wskazują, można ustawić nilw dowolnym momencie
  • Duży zasób, który może wymagać zwolnienia w celu odzyskania pamięci
  • Gdy potrzebujesz sposobu, aby dowiedzieć się, kiedy wartość została ustawiona (dane jeszcze nie załadowane> dane) zamiast korzystać z osobnych danych Boolean

Opcje nie istnieją w Objective-C, ale istnieje równoważna koncepcja, zwracająca zero. Metody, które mogą zwrócić obiekt, mogą zamiast tego zwrócić zero. Ma to oznaczać „brak ważnego obiektu” i często używane jest do powiedzenia, że ​​coś poszło nie tak. Działa tylko z obiektami Objective-C, a nie z prymitywami lub podstawowymi typami C (wyliczenia, struktury). Cel C często nie wyspecjalizowane typy reprezentuje brak tych wartości ( NSNotFoundktóra jest naprawdę NSIntegerMax, kCLLocationCoordinate2DInvalidreprezentuje nieprawidłową współrzędnych -1lub jakąś wartość ujemna są używane). Koder musi wiedzieć o tych specjalnych wartościach, dlatego należy je udokumentować i nauczyć się dla każdego przypadku. Jeśli metoda nie mogła przyjąć,nil parametru, należy to udokumentować. W celu Cnilbył wskaźnikiem, tak jak wszystkie obiekty zostały zdefiniowane jako wskaźniki, ale nilwskazywały na określony (zerowy) adres. W Swift niljest dosłowny, co oznacza brak określonego typu.


W porównaniu do nil

Kiedyś byłeś w stanie użyć dowolnej opcjonalnej jako Boolean:

let leatherTrim: CarExtras? = nil
if leatherTrim {
    price = price + 1000
}

W nowszych wersjach Swift musisz używać leatherTrim != nil. Dlaczego to? Problem polega na tym, że Booleanmożna zawinąć w opcjonalny. Jeśli Booleantak, to:

var ambiguous: Boolean? = false

ma dwa rodzaje „fałszu”, jeden, w którym nie ma wartości, i jeden, w którym ma wartość, ale wartość jest false. Szybka nienawidzi dwuznaczności, więc teraz zawsze musisz sprawdzić opcję przeciw nil.

Zastanawiasz się, jaki jest sens opcjonalności Boolean? Podobnie jak w przypadku innych opcji, .nonestan może wskazywać, że wartość jest jak dotąd nieznana. Na drugim końcu połączenia sieciowego może znajdować się coś, co zajmuje trochę czasu, aby sondować. Opcjonalne booleany nazywane są również „ booleanami trzech wartości


Szybkie sztuczki

Swift wykorzystuje kilka sztuczek, aby umożliwić działanie opcji. Rozważ te trzy linie zwykłego kodu opcjonalnego;

var religiousAffiliation: String? = "Rastafarian"
religiousAffiliation = nil
if religiousAffiliation != nil { ... }

Żadna z tych linii nie powinna się skompilować.

  • Pierwszy wiersz ustawia opcjonalny ciąg znaków za pomocą literału ciągu znaków, dwa różne typy. Nawet jeśli był to Stringtyp, są różne
  • Druga linia ustawia opcjonalny Ciąg na zero, dwa różne typy
  • Trzeci wiersz porównuje opcjonalny ciąg do zera, dwa różne typy

Omówię niektóre szczegóły implementacji opcji, które pozwalają na działanie tych linii.


Tworzenie opcjonalnego

Używanie ?do tworzenia opcjonalnego jest cukrem syntaktycznym, włączanym przez kompilator Swift. Jeśli chcesz to zrobić na dłuższą metę, możesz utworzyć opcjonalne takie jak to:

var name: Optional<String> = Optional("Bob")

Wywołuje Optionalto pierwszy inicjalizator, public init(_ some: Wrapped)który wyprowadza typ opcjonalny z typu używanego w nawiasach.

Jeszcze dłuższy sposób tworzenia i ustawiania opcjonalnego:

var serialNumber:String? = Optional.none
serialNumber = Optional.some("1234")
print("\(serialNumber.debugDescription)")

Ustawienie opcjonalne na nil

Możesz utworzyć opcjonalny bez wartości początkowej lub utworzyć wartość początkową nil(oba mają ten sam wynik).

var name: String?
var name: String? = nil

Umożliwienie równości opcji niljest możliwe dzięki protokołowi ExpressibleByNilLiteral(poprzednio nazwanemu NilLiteralConvertible). Opcjonalny jest tworzony z Optionaldrugim co inicjatora, public init(nilLiteral: ()). Dokumenty mówią, że nie powinieneś używać ExpressibleByNilLiteraldo niczego oprócz opcji, ponieważ zmieniłoby to znaczenie zero w twoim kodzie, ale można to zrobić:

class Clint: ExpressibleByNilLiteral {
    var name: String?
    required init(nilLiteral: ()) {
        name = "The Man with No Name"
    }
}

let clint: Clint = nil // Would normally give an error
print("\(clint.name)")

Ten sam protokół umożliwia ustawienie już utworzonej opcji na nil. Chociaż nie jest to zalecane, możesz użyć inicjatora zerowego dosłowności bezpośrednio:

var name: Optional<String> = Optional(nilLiteral: ())

Porównanie opcjonalnego z nil

Opcje definiują dwa specjalne operatory „==” i „! =”, Które można zobaczyć w Optionaldefinicji. Pierwszy ==pozwala sprawdzić, czy jakakolwiek opcja jest równa zero. Dwie różne opcje, które są ustawione na .none, zawsze będą równe, jeśli powiązane typy są takie same. Kiedy porównujesz do zera, za kulisami Swift tworzy opcjonalny tego samego powiązanego typu, ustaw na .none, a następnie używa go do porównania.

// How Swift actually compares to nil
var tuxedoRequired: String? = nil
let temp: Optional<String> = Optional.none
if tuxedoRequired == temp { // equivalent to if tuxedoRequired == nil
    print("tuxedoRequired is nil")
}

Drugi ==operator umożliwia porównanie dwóch opcji. Oba muszą być tego samego typu i ten typ musi być zgodny Equatable(protokół, który pozwala na porównanie rzeczy ze zwykłym operatorem „==”). Szybki (przypuszczalnie) rozpakowuje dwie wartości i porównuje je bezpośrednio. Obsługuje również przypadek, w którym znajduje się jedna lub obie opcje .none. Zwróć uwagę na różnicę między porównywaniem z nilliterałem.

Ponadto pozwala porównać dowolny Equatabletyp z opcjonalnym opakowaniem tego typu:

let numberToFind: Int = 23
let numberFromString: Int? = Int("23") // Optional(23)
if numberToFind == numberFromString {
    print("It's a match!") // Prints "It's a match!"
}

Za kulisami Swift otacza nieopcjonalne jako opcjonalne przed porównaniem. Działa również z literałami ( if 23 == numberFromString {)

Powiedziałem, że są dwa ==operatory, ale tak naprawdę jest trzeci, który pozwala umieścić nilpo lewej stronie porównania

if nil == name { ... }

Opcje nazewnictwa

Nie ma konwencji Swift dotyczącej nazewnictwa typów opcjonalnych inaczej niż typów nieobowiązkowych. Ludzie unikają dodawania czegoś do nazwy, aby pokazać, że jest ona opcjonalna (np. „OpcjonalnaŚredniaNazwa” lub „możliwaNumerAsString”) i pozwalają deklaracji pokazać, że jest to typ opcjonalny. Staje się to trudne, gdy chcesz nazwać coś, co będzie zawierało wartość opcjonalną. Nazwa „middleName” implikuje, że jest to typ String, więc kiedy wyodrębnisz z niej wartość String, często możesz skończyć z nazwami takimi jak „actualMiddleName” lub „unwrappedMiddleName” lub „realMiddleName”. Użyj opcjonalnego wiązania i ponownie użyj nazwy zmiennej, aby obejść ten problem.


Oficjalna definicja

Z „Podstawy” w Swift Programming Language :

Swift wprowadza również typy opcjonalne, które obsługują brak wartości. Opcjonalne mówią albo: „istnieje wartość i jest ona równa x” lub „w ogóle nie ma wartości”. Opcjonalne są podobne do używania zer ze wskaźnikami w Objective-C, ale działają dla każdego typu, nie tylko klas. Opcje są bezpieczniejsze i bardziej wyraziste niż wskaźniki zero w Objective-C i są sercem wielu najpotężniejszych funkcji Swift.

Opcjonalne są przykładem tego, że Swift jest bezpiecznym językiem. Swift pomaga jasno określić typy wartości, z którymi może współpracować kod. Jeśli część kodu oczekuje ciągu, bezpieczeństwo typu zapobiega przypadkowemu przekazaniu go jako ciągu. Umożliwia to wychwycenie i naprawienie błędów na jak najwcześniejszym etapie procesu programowania.


Na koniec oto wiersz z 1899 roku na temat opcji:

Wczoraj na schodach
spotkałem mężczyznę, którego tam nie było.
Nie było go dzisiaj.
Chciałbym, chciałbym, żeby odszedł

Antigonish


Więcej zasobów:

Nevan King
źródło
5
@KaanDedeoglu Niestety Steve jest bardzo opcjonalny. Był tutaj, a teraz go nie ma.
Nevan King
19
if myStringjuż się nie kompiluje. Trzeba if myString != nil. Zobacz dokumentację .
Pang
5
najlepsze i najjaśniejsze wyjaśnienie? i ! użyj w Swift znalazłem w sieci. dziękuję
Mindbomb,
2
mateo wyjaśnia dogłębnie Opcjonalne, sięgając do Głębi i łatwych przykładów.
iluvatar_GR
4
Dziękuję za to wyjaśnienie, jest znacznie jaśniejsze niż własna dokumentacja Apple.
yesthisisjoe
16

Weźmy przykład: NSErrorjeśli nie zostanie zwrócony błąd, możesz ustawić opcjonalne zwracanie wartości zero. Przypisywanie wartości do wartości nie ma sensu, jeśli nie ma błędu.

var error: NSError? = nil

Pozwala to również na ustawienie wartości domyślnej. Możesz więc ustawić metodę jako wartość domyślną, jeśli funkcja niczego nie przekaże

func doesntEnterNumber(x: Int? = 5) -> Bool {
    if (x == 5){
        return true
    } else {
        return false
    }
}
John Riselvato
źródło
Zdanie „Jeśli to zero, wynik każdego wyrażenia z nim również równego zero” jest po prostu błędne. func isNil<T>(t: T?) -> Bool { return t == nil }zwróci, truenawet jeśli nilw wyrażeniu jest opcjonalna wartość .
zwróć prawdę
Niesamowicie zły przykładowy kod. Nie mógłbyś wymyślić czegoś lepszego? Dlaczego nie po prostu return x == 5? Co jest takiego specjalnego w 5?
Atomosk
Nie, 2 lata temu nie mogłem wymyślić czegoś lepszego. Dzisiaj tak, ale czy to ma sens? tak. Dzięki za dane wejściowe @ Atomosk, jest to naprawdę pomocne.
John Riselvato,
12

Nie możesz mieć zmiennej, która wskazuje nilw Swift - nie ma wskaźników ani wskaźników zerowych. Ale w interfejsie API często chcesz być w stanie wskazać konkretny rodzaj wartości lub jej brak - np. Czy moje okno ma delegata, a jeśli tak, to kto? Opcjonalne są bezpieczne dla typu, bezpieczne dla pamięci metody Swift.

Rickster
źródło
11

Udzieliłem krótkiej odpowiedzi, która podsumowuje większość z powyższych, aby usunąć niepewność, która była w mojej głowie jako początkującego:

W przeciwieństwie do Celu-C żadna zmienna nie może zawierać wartości zerowej w Swift, dlatego dodano opcjonalny typ zmiennej (zmienne z przyrostkiem „?”):

    var aString = nil //error

Duża różnica polega na tym, że zmienne opcjonalne nie przechowują bezpośrednio wartości (tak jak normalne zmienne Obj-C), zawierają dwa stany : „ ma wartość ” lub „ ma zero ”:

    var aString: String? = "Hello, World!"
    aString = nil //correct, now it contains the state "has nil"

W związku z tym możesz sprawdzić te zmienne w różnych sytuacjach:

if let myString = aString? {
     println(myString)
}
else { 
     println("It's nil") // this will print in our case
}

Korzystając z „!” sufiks, możesz również uzyskać dostęp do wartości w nich zawartych , tylko jeśli one istnieją . (tzn. nie jest zero ):

let aString: String? = "Hello, World!"
// var anotherString: String = aString //error
var anotherString: String = aString!

println(anotherString) //it will print "Hello, World!"

Dlatego musisz użyć „?” i "!" i nie używaj ich wszystkich domyślnie. (to było moje największe oszołomienie)

Zgadzam się również z powyższą odpowiedzią: Typu opcjonalnego nie można użyć jako wartości logicznej .

Teodor Ciuraru
źródło
7

W obiektywnych zmiennych C bez wartości były równe „zero” (możliwe było również użycie wartości „zero” takich samych jak 0 i fałsz), dlatego możliwe było użycie zmiennych w instrukcjach warunkowych (Zmienne o wartościach takich samych jak „PRAWDA” ”, a te bez wartości były równe„ FAŁSZ ”).

Swift zapewnia bezpieczeństwo typu, zapewniając „wartość opcjonalną”. tzn. zapobiega powstawaniu błędów spowodowanych przypisywaniem zmiennych różnych typów.

Zatem w Swift można podawać tylko wartości logiczne w instrukcjach warunkowych.

var hw = "Hello World"

Tutaj, mimo że „hw” jest ciągiem, nie można go użyć w instrukcji if, tak jak w celu C.

//This is an error

if hw

 {..}

W tym celu należy go utworzyć jako,

var nhw : String? = "Hello World"

//This is correct

if nhw

 {..}
Gokul
źródło
5

Opcjonalna wartość pozwala pokazać brak wartości. Trochę jak NULL w SQL lub NSNull w Objective-C. Myślę, że będzie to ulepszenie, ponieważ można tego użyć nawet w przypadku typów „prymitywnych”.

// Reimplement the Swift standard library's optional type
enum OptionalValue<T> {
    case None
    case Some(T)
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some(100)

Fragment: Apple Inc. „Swift Programming Language”. iBooks. https://itun.es/gb/jEUH0.l

Maria Zverina
źródło
6
nilto po prostu cukier składniowy dla stałej wyliczeniowej OptionalValue<T>.None(gdzie Tjest typ odpowiedni dla kontekstu, w którym używasz nil). ?jest skrótem do OptionalValue<T>.Some(T).
rickster
4

Opcjonalne oznacza, że ​​Swift nie jest całkowicie pewien, czy wartość odpowiada typowi: na przykład Int? oznacza, że ​​Swift nie jest całkowicie pewien, czy liczba jest liczbą całkowitą.

Aby go usunąć, możesz zastosować trzy metody.

1) Jeśli masz absolutną pewność co do typu, możesz użyć wykrzyknika, aby wymusić jego rozpakowanie, w następujący sposób:

// Here is an optional variable:

var age: Int?

// Here is how you would force unwrap it:

var unwrappedAge = age!

Jeśli wymusisz rozpakowanie opcjonalnego i jest on równy zero, możesz napotkać ten błąd awarii:

wprowadź opis zdjęcia tutaj

To niekoniecznie jest bezpieczne, więc oto metoda, która może zapobiec awarii w przypadku, gdy nie masz pewności co do typu i wartości:

Metody 2 i 3 chronią przed tym problemem.

2) Opcja niejawnie nieopakowana

 if let unwrappedAge = age {

 // continue in here

 }

Zauważ, że rozpakowanym typem jest teraz Int , a nie Int? .

3) Strażnik

 guard let unwrappedAge = age else { 
   // continue in here
 }

Stąd możesz zacząć od rozpakowanej zmiennej. Pamiętaj, aby wymusić odwijanie (za pomocą!), Jeśli jesteś pewien typu zmiennej.

Powodzenia w projekcie!

GJZ
źródło
1

Kiedy zacząłem się uczyć Swift, bardzo trudno było zrozumieć, dlaczego jest to opcjonalne .

Pomyślmy w ten sposób. Rozważmy klasę, Personktóra ma dwie właściwości namei company.

class Person: NSObject {

    var name : String //Person must have a value so its no marked as optional
    var companyName : String? ///Company is optional as a person can be unemployed that is nil value is possible

    init(name:String,company:String?) {

        self.name = name
        self.companyName = company

    }
}

Teraz pozwala stworzyć kilka obiektów Person

var tom:Person = Person.init(name: "Tom", company: "Apple")//posible
var bob:Person = Person.init(name: "Bob", company:nil) // also Possible because company is marked as optional so we can give Nil

Ale nie możemy przejść Nildoname

var personWithNoName:Person = Person.init(name: nil, company: nil)

Teraz Porozmawiajmy o tym, dlaczego używamy optional?. Rozważmy sytuację, w której chcemy dodać Incpo nazwie firmy jak applebędzie apple Inc. Musimy dołączyć Incpo nazwie firmy i wydruku.

print(tom.companyName+" Inc") ///Error saying optional is not unwrapped.
print(tom.companyName!+" Inc") ///Error Gone..we have forcefully unwrap it which is wrong approach..Will look in Next line
print(bob.companyName!+" Inc") ///Crash!!!because bob has no company and nil can be unwrapped.

Teraz zbadajmy, dlaczego ma miejsce opcjonalność.

if let companyString:String = bob.companyName{///Compiler safely unwrap company if not nil.If nil,no unwrap.

    print(companyString+" Inc") //Will never executed and no crash!!!
}

Pozwala zastąpić bobztom

if let companyString:String = tom.companyName{///Compiler safely unwrap company if not nil.If nil,no unwrap.

    print(companyString+" Inc") //Will never executed and no crash!!!
}

I gratulacje! mamy właściwie do czynieniaoptional?

Tak więc są punkty realizacji

  1. Oznaczymy zmienną jako opcjonalną, jeśli jest to możliwe nil
  2. Jeśli chcemy użyć tej zmiennej gdzieś w kompilatorze kodu, przypomnimy, że musimy sprawdzić, czy mamy do czynienia z tą zmienną, jeśli ona zawiera nil.

Dziękuję ... Szczęśliwego kodowania

Tunvir Rahman Tusher
źródło
0

Pozwala eksperymentować z poniższym kodem Plac zabaw. Mam nadzieję, że wyjaśnię, co jest opcjonalne i dlaczego go używam.

var sampleString: String? ///Optional, Possible to be nil

sampleString = nil ////perfactly valid as its optional

sampleString = "some value"  //Will hold the value

if let value = sampleString{ /// the sampleString is placed into value with auto force upwraped.

    print(value+value)  ////Sample String merged into Two
}

sampleString = nil // value is nil and the

if let value = sampleString{

    print(value + value)  ///Will Not execute and safe for nil checking
}

//   print(sampleString! + sampleString!)  //this line Will crash as + operator can not add nil
Tunvir Rahman Tusher
źródło
0

Od https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html :

Opcjonalne tworzenie łańcuchów to proces sprawdzania i wywoływania właściwości, metod i indeksów opcjonalnych, które mogą być obecnie zerowe. Jeśli opcjonalny zawiera wartość, właściwość, metoda lub wywołanie indeksu dolnego kończy się powodzeniem; jeśli opcjonalne jest zero, właściwość, metoda lub wywołanie indeksu dolnego zwraca zero. Wiele zapytań można łączyć razem, a cały łańcuch kończy się niepowodzeniem, jeśli jakiekolwiek ogniwo w łańcuchu jest zerowe.

Aby lepiej zrozumieć, przeczytaj powyższy link.

nizama bunti
źródło
0

Dobrze...

? (Opcjonalnie) oznacza, że ​​twoja zmienna może zawierać wartość zero podczas gdy ! (uncrapper) wskazuje, że twoja zmienna musi mieć pamięć (lub wartość), kiedy jest używana (próbowała uzyskać z niej wartość) w czasie wykonywania.

Główną różnicą jest to, że opcjonalne łączenie łańcuchów kończy się niepowodzeniem, gdy opcjonalne jest zerowe, natomiast wymuszone rozpakowywanie powoduje błąd czasu wykonywania, gdy opcjonalne jest zerowe.

Aby odzwierciedlić fakt, że opcjonalne łączenie łańcuchowe można wywołać na wartość zero, wynik opcjonalnego wywołania łańcuchowego jest zawsze wartością opcjonalną, nawet jeśli właściwość, metoda lub indeks dolny, którego dotyczy zapytanie, zwraca wartość nieobowiązkową. Za pomocą tej opcjonalnej wartości zwrotnej można sprawdzić, czy opcjonalne połączenie łańcuchowe zakończyło się powodzeniem (zwrócona opcja zawiera wartość) lub nie powiodła się z powodu zerowej wartości w łańcuchu (zwrócona wartość opcjonalna to zero).

W szczególności wynik opcjonalnego połączenia łańcuchowego jest tego samego typu co oczekiwana wartość zwracana, ale jest zawarty w opcjonalnym. Właściwość, która normalnie zwraca Int, zwróci Int? przy dostępie poprzez opcjonalne łączenie.

var defaultNil : Int?  // declared variable with default nil value
println(defaultNil) >> nil  

var canBeNil : Int? = 4
println(canBeNil) >> optional(4)

canBeNil = nil
println(canBeNil) >> nil

println(canBeNil!) >> // Here nil optional variable is being unwrapped using ! mark (symbol), that will show runtime error. Because a nil optional is being tried to get value using unwrapper

var canNotBeNil : Int! = 4
print(canNotBeNil) >> 4

var cantBeNil : Int = 4
cantBeNil = nil // can't do this as it's not optional and show a compile time error

Oto szczegółowy podstawowy samouczek opracowany przez Apple Developer Committee: Opcjonalne tworzenie łańcuchów

Krunal
źródło
0

Opcjonalny w Swift to typ, który może przechowywać wartość lub nie zawierać żadnej wartości. Opcjonalne są napisane przez dodanie ? do dowolnego typu:

var name: String?

Możesz skorzystać z tego linku, aby uzyskać głębszą wiedzę: https://medium.com/@agoiabeladeyemi/optionals-in-swift-2b141f12f870

Vicky Prajapati
źródło
-1

Oto równoważna opcjonalna deklaracja w Swift:

var middleName: String?

Ta deklaracja tworzy zmienną o nazwie middleName typu String. Znak zapytania (?) Po typie zmiennej String wskazuje, że zmienna middleName może zawierać wartość, która może być String lub zero. Każdy, kto patrzy na ten kod, natychmiast wie, że middleName może być zerowy. To jest samo dokumentowanie!

Jeśli nie określisz wartości początkowej dla opcjonalnej stałej lub zmiennej (jak pokazano powyżej), wartość zostanie automatycznie ustawiona na zero. Jeśli wolisz, możesz jawnie ustawić wartość początkową na zero:

var middleName: String? = nil

Aby uzyskać więcej informacji na temat opcjonalnego przeczytaj poniższy link

http://www.iphonelife.com/blog/31369/swift-101-working-swifts-new-optional-values

Devendra Agnihotri
źródło
użyj tego, var middleName: String! = ""
Gaurav