Szukaj…


Wprowadzenie

„Opcjonalna wartość albo zawiera wartość, albo zero, wskazując brak wartości”

Fragment: Apple Inc. „Swift Programming Language (wydanie Swift 3.1).” iBooks. https://itun.es/us/k5SW7.l

Podstawowe opcjonalne przypadki użycia obejmują: dla stałej (let), użycie opcjonalnej w pętli (jeśli-let), bezpieczne rozpakowanie opcjonalnej wartości w ramach metody (straż-let) i jako część pętli przełączania (case-let ), domyślnie wartość wynosi zero, przy użyciu operatora koalescencji (??)

Składnia

  • var opcjonalnyNazwa: opcjonalnyTyp? // zadeklaruj typ opcjonalny, domyślnie zero
  • var opcjonalnyNazwa: opcjonalnyTyp? = wartość // deklaruj opcjonalne z wartością
  • var opcjonalnyNazwa: opcjonalnyTyp! // zadeklaruj domyślnie nieopakowane opcjonalne
  • opcjonalny! // wymuś rozpakowanie opcjonalnego

Uwagi

Aby uzyskać więcej informacji na temat opcji, zobacz Swift Programming Language .

Rodzaje opcji

Opcjonalne to ogólny typ wyliczenia, który działa jak opakowanie. To opakowanie pozwala zmiennej mieć jeden z dwóch stanów: wartość typu zdefiniowanego przez użytkownika lub nil , która reprezentuje brak wartości.

Ta umiejętność jest szczególnie ważna w Swift, ponieważ jednym z deklarowanych celów projektowych języka jest dobra współpraca z platformami Apple. Wiele (większość) frameworków Apple wykorzystuje nil ze względu na łatwość użycia i znaczenie dla wzorców programowania i projektowania API w Objective-C.

W Swift, aby zmienna miała wartość nil , musi być opcjonalna. Opcjonalnie można utworzyć, dołączając albo ! lub ? do typu zmiennej. Na przykład, aby uczynić Int opcjonalnym, możesz użyć

var numberOne: Int! = nil
var numberTwo: Int? = nil

? opcjonalne muszą być jawnie rozpakowane i powinny być używane, jeśli nie jesteś pewien, czy zmienna będzie miała wartość, kiedy ją uzyskasz. Na przykład po przekształceniu łańcucha w Int , wynikiem jest opcjonalny Int? , ponieważ zero zostanie zwrócone, jeśli ciąg nie jest poprawną liczbą

let str1 = "42"
let num1: Int? = Int(str1) // 42

let str2 = "Hello, World!"
let num2: Int? = Int(str2) // nil

! opcjonalne są automatycznie rozpakowywane i powinny być używane tylko wtedy, gdy masz pewność, że zmienna będzie miała wartość, gdy ją uzyskasz. Na przykład globalny przycisk UIButton! zmienna zainicjowana w viewDidLoad()

//myButton will not be accessed until viewDidLoad is called,
//so a ! optional can be used here
var myButton: UIButton!

override func viewDidLoad(){
    self.myButton = UIButton(frame: self.view.frame)
    self.myButton.backgroundColor = UIColor.redColor()
    self.view.addSubview(self.myButton)
}

Rozpakowywanie opcjonalnego

Aby uzyskać dostęp do wartości opcji, należy ją rozpakować.

Możesz warunkowo rozpakować Opcjonalne za pomocą opcjonalnego wiązania i wymusić rozpakowanie Opcjonalnego za pomocą ! operator.

Warunkowe rozpakowywanie skutecznie pyta „Czy ta zmienna ma wartość?” podczas wymuszania rozpakowywania mówi „Ta zmienna ma wartość!”.

Jeśli wymusisz rozpakowanie zmiennej, która jest nil , twój program rzuci nieoczekiwanie znalezione zero podczas rozpakowywania opcjonalnego wyjątku i zawiesi się, więc musisz uważnie rozważyć użycie ! jest odpowiednie.

var text: String? = nil
var unwrapped: String = text! //crashes with "unexpectedly found nil while unwrapping an Optional value"

W celu bezpiecznego rozpakowania można użyć instrukcji if-let , która nie zgłosi wyjątku ani nie zawiesi się, jeśli zapakowana wartość wynosi nil :

var number: Int?
if let unwrappedNumber = number {       // Has `number` been assigned a value?
    print("number: \(unwrappedNumber)") // Will not enter this line
} else {
    print("number was not assigned a value")
}

Lub oświadczenie straży :

var number: Int?
guard let unwrappedNumber = number else {
    return
}
print("number: \(unwrappedNumber)")

Zauważ, że zakres zmiennej unwrappedNumber znajduje się wewnątrz instrukcji if-let i poza blokiem guard .

Możesz rozpakować łańcuch wielu opcji, jest to przydatne głównie w przypadkach, gdy twój kod wymaga więcej niż zmiennej do poprawnego działania:

var firstName:String?
var lastName:String?

if let fn = firstName, let ln = lastName {
    print("\(fn) + \(ln)")//pay attention that the condition will be true only if both optionals are not nil.
}

Zauważ, że wszystkie zmienne muszą być rozpakowane, aby pomyślnie przejść test, w przeciwnym razie nie byłoby sposobu, aby określić, które zmienne zostały rozpakowane, a które nie.

Możesz łańcuchować instrukcje warunkowe za pomocą opcji opcjonalnych natychmiast po ich rozpakowaniu. Oznacza to brak zagnieżdżonych instrukcji if - else!

var firstName:String? = "Bob"
var myBool:Bool? = false

if let fn = firstName, fn == "Bob", let bool = myBool, !bool {
    print("firstName is bob and myBool was false!")
}

Brak operatora koalescencyjnego

Możesz użyć zerowego operatora koalescencyjnego, aby rozpakować wartość, jeśli jest ona inna niż zero, w przeciwnym razie podaj inną wartość:

func fallbackIfNil(str: String?) -> String {
    return str ?? "Fallback String"
}
print(fallbackIfNil("Hi")) // Prints "Hi"
print(fallbackIfNil(nil)) // Prints "Fallback String"

Ten operator może zwierać , co oznacza, że jeśli lewy operand jest inny niż zero, prawy operand nie zostanie oceniony:

func someExpensiveComputation() -> String { ... }

var foo : String? = "a string"
let str = foo ?? someExpensiveComputation()

W tym przykładzie, ponieważ foo ma wartość someExpensiveComputation() niż zero, someExpensiveComputation() nie zostaną wywołane.

Możesz także połączyć wiele zerowych instrukcji koalescencyjnych:

var foo : String?
var bar : String?

let baz = foo ?? bar ?? "fallback string"

W tym przykładzie baz zostanie przypisana nieopakowana wartość foo jeśli jest ona inna niż zero, w przeciwnym razie zostanie mu przypisana nieopakowana wartość bar jeśli jest ona inna niż zero, w przeciwnym razie zostanie przypisana wartość zastępcza.

Opcjonalne łączenie

Za pomocą opcjonalnego łączenia można wywoływać metodę , uzyskiwać dostęp do właściwości lub indeksować opcjonalnie. Odbywa się to poprzez umieszczenie ? pomiędzy podaną zmienną opcjonalną a danym elementem (metoda, właściwość lub indeks dolny).

struct Foo {
    func doSomething() {
        print("Hello World!")
    }
}

var foo : Foo? = Foo()

foo?.doSomething() // prints "Hello World!" as foo is non-nil

Jeśli foo zawiera wartość, zostanie do niej wywołana doSomething() . Jeśli foo jest nil , nic złego się nie stanie - kod po prostu po cichu zawiedzie i będzie kontynuował wykonywanie.

var foo : Foo? = nil

foo?.doSomething() // will not be called as foo is nil

(Jest to podobne zachowanie jak wysyłanie wiadomości do nil w Objective-C)

Powodem, dla którego opcjonalne łączenie łańcuchowe jest nazywane, jest to, że „opcjonalność” będzie propagowana przez członków, do których dzwonisz / do których masz dostęp. Oznacza to, że zwracane wartości dowolnych elementów używanych z opcjonalnym łączeniem łańcuchowym będą opcjonalne, niezależnie od tego, czy są wpisane jako opcjonalne czy nie.

struct Foo {
    var bar : Int
    func doSomething() { ... }
}

let foo : Foo? = Foo(bar: 5)
print(foo?.bar) // Optional(5)

Tutaj foo?.bar zwraca Int? nawet jeśli bar nie jest opcjonalny, ponieważ sam foo jest opcjonalny.

W miarę propagowania opcjonalności metody zwracające Void zwrócą Void? po wywołaniu z opcjonalnym łańcuchem. Może to być przydatne w celu ustalenia, czy metoda została wywołana, czy nie (a zatem, czy opcjonalna ma wartość).

let foo : Foo? = Foo()

if foo?.doSomething() != nil {
    print("foo is non-nil, and doSomething() was called")
} else {
    print("foo is nil, therefore doSomething() wasn't called")
}

Czy porównujemy Void? zwraca wartość nil w celu ustalenia, czy metoda została wywołana (a zatem czy foo jest inne niż zero).

Omówienie - dlaczego opcjonalne?

Często podczas programowania konieczne jest rozróżnienie między zmienną, która ma wartość, a zmienną, która jej nie ma. Dla typów referencyjnych, takich jak Wskaźniki C, można użyć specjalnej wartości, takiej jak null aby wskazać, że zmienna nie ma żadnej wartości. W przypadku typów wewnętrznych, takich jak liczba całkowita, jest to trudniejsze. Można użyć wartości nominalnej, takiej jak -1, ale zależy to od interpretacji wartości. Eliminuje również tę „specjalną” wartość z normalnego użytkowania.

Aby rozwiązać ten problem, Swift pozwala zadeklarować dowolną zmienną jako opcjonalną. Wskazuje na to użycie znaku? lub! po typie (patrz Rodzaje opcji )

Na przykład,

var possiblyInt: Int?

deklaruje zmienną, która może zawierać wartość całkowitą lub nie.

Specjalna wartość nil wskazuje, że do tej zmiennej nie jest obecnie przypisana żadna wartość.

possiblyInt = 5      // PossiblyInt is now 5
possiblyInt = nil    // PossiblyInt is now unassigned

nil może być również użyte do przetestowania przypisanej wartości:

if possiblyInt != nil {
    print("possiblyInt has the value \(possiblyInt!)")
}

Zwróć uwagę na użycie ! w instrukcji print, aby rozpakować wartość opcjonalną.

Jako przykład powszechnego użycia opcji, rozważ funkcję, która zwraca liczbę całkowitą z ciągu zawierającego cyfry; Możliwe, że ciąg może zawierać znaki niecyfrowe, a nawet może być pusty.

W jaki sposób funkcja zwracająca prosty Int wskazywać na awarię? Nie można tego zrobić, zwracając określoną wartość, ponieważ uniemożliwiłoby to parsowanie tej wartości z łańcucha.

var someInt
someInt = parseInt("not an integer") // How would this function indicate failure?

Jednak w Swift ta funkcja może po prostu zwrócić opcjonalny Int. Błąd jest wskazywany przez wartość zwracaną nil .

var someInt?
someInt = parseInt("not an integer")  // This function returns nil if parsing fails
if someInt == nil {
    print("That isn't a valid integer")
}


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow