Co oznacza "błąd krytyczny: nieoczekiwanie znaleziono zero podczas rozpakowywania wartości opcjonalnej"?

Mój program Swift zawiesza się z EXC_BAD_INSTRUCTION i tym błędem. Co to znaczy i jak to naprawić?

Błąd krytyczny: nieoczekiwanie znaleziono zero podczas rozpakowywania opcjonalnej wartości


Ten post jest przeznaczony do zbierania odpowiedzi na" nieoczekiwanie znalezione zero " problemy, więc nie są rozproszone i trudne do znalezienia. Możesz dodać własną odpowiedź lub edytować istniejącą odpowiedź wiki.

Author: jtbandes, 2015-08-23

8 answers

ta odpowiedź to community wiki . Jeśli uważasz, że może być lepiej, nie krępuj się edytować go!

Background: Co To jest opcja?

W Swift, Optional jest typem ogólnym , który może zawierać wartość (dowolnego rodzaju) lub w ogóle nie ma wartości.

W wielu innych językach programowania wartość "sentinel" jest często używana do wskazania braku wartości . Na przykład w Objective-C, nil (wskaźnik null) wskazuje na brak obiektu. Ale robi się to trudniejsze podczas pracy z typami prymitywnymi-czy -1 powinno być używane do wskazania braku liczby całkowitej, a może INT_MIN, lub innej liczby całkowitej? Jeśli jakakolwiek konkretna wartość ma oznaczać "brak liczby całkowitej", oznacza to, że nie może być już traktowana jako wartość valid.

Swift jest językiem bezpiecznym dla typów, co oznacza, że język pomaga jasno określić typy wartości, które może zawierać Twój kod pracuj z. Jeśli część kodu spodziewa się ciągu znaków, Typ safety uniemożliwia podanie przez pomyłkę Int.

W Swift, każdy typ może być opcjonalny . Wartość opcjonalna może przyjąć dowolną wartość z oryginalnego typu, lub wartość specjalna nil.

Opcje są zdefiniowane za pomocą przyrostka ? na typ:

var anInt: Int = 42
var anOptionalInt: Int? = 42
var anotherOptionalInt: Int?    // `nil` is the default when no value is provided

Brak wartości w opcji jest oznaczany przez nil:

anOptionalInt = nil

(zauważ, że to {[26] } nie jest tym samym co nil W Objective-C. w Objective-C, nil oznacza brak ważnego wskaźnika obiektu; W Swift opcje nie są ograniczone do obiektów/typów referencyjnych. Opcjonalne zachowuje się podobnie do Haskella Maybe .)


Dlaczego otrzymałem " fatal error: nieoczekiwanie znaleziono zero podczas rozpakowywania opcjonalnej wartości"?

W celu uzyskania dostępu do opcjonalnego wartość (jeśli w ogóle ma taką wartość), musisz ją rozpakować . Wartość opcjonalną można rozpakować bezpiecznie lub siłą. Jeśli wymusisz rozpakowanie opcji, a nie ma wartości, Twój program zawiesi się z powyższym Komunikatem.

Xcode pokaże Ci awarię, podświetlając linię kodu. Problem występuje na tej linii.

crashed line

Ten wypadek może wystąpić z dwoma różnymi rodzajami siły-rozpakowania:

1. Explicit Siła Rozpakowywania

Odbywa się to za pomocą operatora ! na opcjonalnym. Na przykład:

let anOptionalString: String?
print(anOptionalString!) // <- CRASH

Ponieważ anOptionalString jest nil tutaj, dostaniesz awarię na linii, gdzie wymusisz jej rozpakowanie.

2. Bezwarunkowo Rozpakowane Opcje

Są one definiowane przez !, a nie ? po typie.

var optionalDouble: Double!   // this value is implicitly unwrapped wherever it's used

Zakłada się, że te opcje zawierają wartość. Dlatego za każdym razem, gdy uzyskasz dostęp do niejawnie rozpakowanej opcji, Automatycznie być siłą rozpakowany dla Ciebie. Jeśli nie zawiera wartości, ulegnie awarii.

print(optionalDouble) // <- CRASH

Aby ustalić, która zmienna spowodowała awarię, możesz przytrzymać podczas klikania, aby wyświetlić definicję, gdzie można znaleźć opcjonalny Typ.

Iboutlety, w szczególności, są zwykle domyślnie rozpakowanymi opcjami. Dzieje się tak dlatego, że Twój xib lub storyboard połączy gniazda w czasie wykonywania, po inicjalizacji. W związku z tym należy upewnij się, że nie masz dostępu do gniazdek przed ich załadowaniem. Należy również sprawdzić, czy połączenia są poprawne w pliku storyboard / xib, w przeciwnym razie wartości będą nil w czasie wykonywania, a zatem ulegną awarii, gdy zostaną domyślnie rozpakowane.


Kiedy mam wymusić rozpakowanie opcji?

Explicit Force Unwrapping

Ogólnie rzecz biorąc, nigdy nie należy wymusić rozpakowywania opcji za pomocą operatora !. Mogą wystąpić przypadki gdzie użycie ! jest dopuszczalne – ale powinieneś używać go tylko wtedy, gdy masz 100% pewności, że opcja zawiera wartość.

Chociaż istnieje może być okazja, gdzie można użyć siły rozpakowywania, jak wiesz dla fakt , że opcjonalny zawiera wartość – nie ma pojedynczego miejsca, w którym nie można bezpiecznie rozpakować tego opcjonalnego zamiast.

Implicite Unwrapped Optionals

Te zmienne są zaprojektowane tak, aby można było odroczyć ich przypisanie na później w kodzie. To jest Twój odpowiedzialność, aby upewnić się, że mają wartość, zanim uzyskasz do nich dostęp. Jednakże, ponieważ wiążą się one z siłą rozpakowywania, nadal są z natury niebezpieczne – ponieważ {126]}zakładają {127]}, że twoja wartość nie jest zerowa, nawet jeśli przypisanie nil jest ważne.

Powinieneś używać tylko domyślnie rozpakowanych opcji jako w ostateczności . Jeśli możesz użyć lazy zmienna , lub podać wartość domyślną dla zmiennej – powinieneś to zrobić zamiast używać domyślnie rozpakowanego opcjonalnego.

Jednak istnieje kilka scenariuszy, w których domyślnie rozpakowane opcje są korzystne, i nadal możesz używać różnych sposobów bezpiecznego rozpakowywania ich, jak wymieniono poniżej – ale powinieneś {126]}zawsze {127]} używać ich z należytą ostrożnością.


Jak mogę bezpiecznie poradzić sobie z opcjami?

Najprostszy można sprawdzić, czy opcja zawiera wartość, porównując ją z nil.

if anOptionalInt != nil {
    print("Contains a value!")
} else {
    print("Doesn’t contain a value.")
}

Jednak w 99,9% przypadków podczas pracy z opcjami, będziesz chciał uzyskać dostęp do wartości, które zawiera, jeśli w ogóle ją zawiera. Aby to zrobić, możesz użyć opcjonalnego wiązania.

Oprawa Opcjonalna

Opcjonalne Wiązanie pozwala sprawdzić, czy opcja zawiera wartość – i pozwala przypisać rozpakowaną wartość do nowej zmiennej lub stałej. Wykorzystuje składnia if let x = anOptional {...} lub if var x = anOptional {...}, w zależności od tego, czy trzeba zmodyfikować wartość nowej zmiennej po jej powiązaniu.

Na przykład:

if let number = anOptionalInt {
    print("Contains a value! It is \(number)!")
} else {
    print("Doesn’t contain a number")
}

Najpierw sprawdza, czy opcja zawiera wartość. Jeśli robi , to wartość' unwrapped ' jest przypisana do nowej zmiennej (number) – którą możesz swobodnie używać, jakby nie była opcjonalna. Jeśli opcjonalne nie zawiera wartości, to zostanie wywołana klauzula else, tak jak spodziewaj się.

Co jest fajne w opcjonalnym wiązaniu, to można rozpakować wiele opcji w tym samym czasie. Możesz po prostu oddzielić wypowiedzi przecinkiem. Oświadczenie powiedzie się, jeśli wszystkie opcje zostaną rozpakowane.

var anOptionalInt : Int?
var anOptionalString : String?

if let number = anOptionalInt, let text = anOptionalString {
    print("anOptionalInt contains a value: \(number). And so does anOptionalString, it’s: \(text)")
} else {
    print("One or more of the optionals don’t contain a value")
}

Kolejna fajna sztuczka polega na tym, że można również użyć przecinków, aby sprawdzić określony warunek na wartości, po rozpakowaniu go.

if let number = anOptionalInt, number > 0 {
    print("anOptionalInt contains a value: \(number), and it’s greater than zero!")
}

Jedynym haczykiem z użyciem opcjonalnego wiązania wewnątrz instrukcji if jest to, że możesz uzyskać dostęp tylko do unwrapped value from within the scope of the statement. Jeśli potrzebujesz dostępu do wartości spoza zakresu instrukcji, możesz użyć instrukcji guard .

A Instrukcja guard pozwala zdefiniować warunek sukcesu – a bieżący zakres będzie nadal wykonywany tylko wtedy, gdy warunek ten jest spełniony. Są one zdefiniowane za pomocą składni guard condition else {...}.

Tak więc, aby użyć ich z opcjonalnym wiązaniem, możesz to zrobić:]}
guard let number = anOptionalInt else {
    return
}

(Uwaga że wewnątrz Korpusu Strażników, musisz użyć jednej z instrukcji transferu kontrolnego , aby wyjść z zakresu aktualnie wykonywanego kodu).

Jeśli anOptionalInt zawiera wartość, zostanie ona rozpakowana i przypisana do nowej stałej number. Kod po strażnik będzie kontynuował wykonywanie. Jeśli nie zawiera wartości – strażnik wykona kod w nawiasach, co doprowadzi do przeniesienia kontroli, tak aby Kod natychmiast po nie zostanie wykonana.

Prawdziwą zaletą instrukcji guard jest to, że wartość unwrapped jest teraz dostępna do użycia w kodzie, który podąża za instrukcją (ponieważ wiemy, że przyszły kod może tylko wykonać, jeśli opcja ma wartość). Jest to świetne rozwiązanie do wyeliminowania 'pyramids of doom' stworzonego przez zagnieżdżenie wielu poleceń if.

Na przykład:

guard let number = anOptionalInt else {
    return
}

print("anOptionalInt contains a value, and it’s: \(number)!")

Strażnicy również wspierają te same sprytne sztuczki, które twierdzenie if obsługiwane, takie jak rozpakowanie wielu opcji jednocześnie i użycie klauzuli where.

To, czy użyjesz instrukcji if czy guard, zależy całkowicie od tego, czy jakikolwiek przyszły kod wymaga opcjonalnego, aby zawierał wartość.

Operator Zerowy

Zerowy Operator koalescencyjny jest sprytną skróconą wersją trójdzielnego operatora warunkowego , zaprojektowanego głównie do konwersji opcji na opcje nieobsługiwane. Posiada składnia a ?? b, gdzie a jest typem opcjonalnym, a {[53] } jest tym samym typem co a (chociaż zwykle nie jest opcjonalny).

Zasadniczo pozwala powiedzieć " jeśli a zawiera wartość, rozpakuj ją. If it doesn 't then return b instead". Na przykład możesz go użyć w następujący sposób:

let number = anOptionalInt ?? 0

To zdefiniuje number stałą typu Int, która będzie zawierać wartość anOptionalInt, jeśli zawiera wartość, lub 0 W przeciwnym razie.

To tylko skrót za:

let number = anOptionalInt != nil ? anOptionalInt! : 0

Opcjonalne Łańcuchowanie

Możesz użyć opcjonalnego łańcucha w celu wywołania metody lub uzyskania dostępu do właściwości na opcjonalnym. Jest to po prostu zrobione przez dodanie nazwy zmiennej ? podczas jej używania.

Na przykład, powiedzmy, że mamy zmienną foo, o typie opcjonalnej instancji Foo.

var foo : Foo?

Jeśli chcemy wywołać metodę na foo, która niczego nie zwraca, możemy po prostu zrobić: {116]}

foo?.doSomethingInteresting()

Jeśli foo zawiera value, ta metoda zostanie na niej wywołana. Jeśli tak się nie stanie, nic złego się nie stanie – kod będzie po prostu kontynuowany.

(jest to podobne zachowanie do wysyłania wiadomości do nil W Objective-C)

Może to być również używane do ustawiania właściwości oraz metod wywołania. Na przykład:

foo?.bar = Bar()

Ponownie, nic złego się tu nie stanie, jeśli foo jest nil. Twój kod będzie po prostu kontynuowany.

Kolejna fajna sztuczka, która chaining pozwala sprawdzić, czy ustawienie właściwości lub wywołanie metody zakończyło się sukcesem. Można to zrobić porównując wartość zwracaną do nil.

(to dlatego, że opcjonalna wartość zwróci Void? zamiast Void w metodzie, która niczego nie zwraca)

Na przykład:

if (foo?.bar = Bar()) != nil {
    print("bar was set successfully")
} else {
    print("bar wasn’t set successfully")
}

Jednak sytuacja staje się nieco trudniejsza, gdy próbuje uzyskać dostęp do Właściwości lub metod wywołania, które zwracają wartość. Ponieważ {[62] } jest opcjonalne, wszystko, co z niego zostanie zwrócone, będzie również opcjonalne. Aby sobie z tym poradzić, możesz albo rozpakować opcje zwracane przy użyciu jednej z powyższych metod – albo rozpakować {62]} przed uzyskaniem dostępu do metod lub wywołaniem metod zwracających wartości.

Ponadto, jak sama nazwa wskazuje, możesz "połączyć" te stwierdzenia. Oznacza to, że jeśli foo ma opcjonalną właściwość baz, która ma właściwość {–76]} - możesz napisać co następuje:

let optionalQux = foo?.baz?.qux

Ponownie, ponieważ foo i baz są opcjonalne, wartość zwracana z qux zawsze będzie opcjonalna niezależnie od tego, czy sama qux jest opcjonalna.

map i flatMap

Często nieużywaną funkcją z opcjami jest możliwość korzystania z funkcji map i flatMap. Umożliwiają one stosowanie nieobowiązkowych przekształceń do zmiennych opcjonalnych. Jeśli opcja ma wartość, można zastosować do niej daną transformację. Jeśli nie ma wartości, pozostanie nil.

Na przykład, Załóżmy, że masz opcjonalny ciąg znaków:

let anOptionalString:String?

Poprzez zastosowanie do niego funkcji {[81–} - możemy użyć funkcji stringByAppendingString, aby połączyć ją z innym łańcuchem znaków.

Ponieważ stringByAppendingString pobiera nieobowiązkowy argument string, nie możemy bezpośrednio wprowadzić naszego opcjonalnego ciągu. Jednak, używając map, możemy użyć allow stringByAppendingString, jeśli anOptionalString ma wartość.

Na przykład:

var anOptionalString:String? = "bar"

anOptionalString = anOptionalString.map {unwrappedString in
    return "foo".stringByAppendingString(unwrappedString)
}

print(anOptionalString) // Optional("foobar")

Jeśli jednak anOptionalString nie ma wartości, map zwróci nil. Na przykład:

var anOptionalString:String?

anOptionalString = anOptionalString.map {unwrappedString in
    return "foo".stringByAppendingString(unwrappedString)
}

print(anOptionalString) // nil

flatMap działa podobnie do map, z tym, że pozwala zwrócić inny opcjonalny z wewnątrz ciała zamknięcia. Oznacza to, że możesz wprowadzić opcjonalne do procesu, który wymaga nieobowiązkowego wejścia, ale może sam wyjść opcjonalne.

try!

System obsługi błędów Swift może być bezpiecznie używany z Do-Try-Catch :

do {
    let result = try someThrowingFunc() 
} catch {
    print(error)
}

Jeśli someThrowingFunc() wyrzuci błąd, błąd zostanie bezpiecznie złapany w catch blok.

Stała error widoczna w bloku catch nie została przez nas zadeklarowana - jest automatycznie generowana przez catch.

Możesz również zadeklarować error samodzielnie, ma tę zaletę, że jest w stanie wrzucić go do użytecznego formatu, na przykład:

do {
    let result = try someThrowingFunc()    
} catch let error as NSError {
    print(error.debugDescription)
}

Używanie try w ten sposób jest właściwym sposobem na próbowanie, wychwytywanie i radzenie sobie z błędami wynikającymi z funkcji rzucania.

Istnieje również try? który pochłania błąd:

if let result = try? someThrowingFunc() {
    // cool
} else {
    // handle the failure, but there's no error information available
}

Ale System obsługi błędów Swift zapewnia również sposób na "wymuszenie próby" za pomocą try!:

let result = try! someThrowingFunc()

Pojęcia wyjaśnione w tym poście również mają zastosowanie tutaj: jeśli błąd zostanie wyrzucony, aplikacja ulegnie awarii.

powinieneś używać try! tylko wtedy, gdy możesz udowodnić, że jego wynik nigdy nie zawiedzie w Twoim kontekście - i to jest bardzo rzadkie.

Przez większość czasu będziesz używać kompletnego systemu Do-Try-Catch - i opcjonalnego, try?, W rzadkich przypadkach, gdy obsługa błędu nie jest ważna.


Zasoby

 530
Author: Hamish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-03 17:57:23

TL; DR odpowiedź

Z bardzo nielicznymi wyjątkami , reguła ta jest złota:

Unikać stosowania !

Declare variable optional (?), not unwrapped optionals (IUO) (!)

Innymi słowy, raczej używać:
var nameOfDaughter: String?

Zamiast:
var nameOfDaughter: String!

Rozpakuj opcjonalną zmienną za pomocą if let lub guard let

Albo rozpakuj zmienną tak:

if let nameOfDaughter = nameOfDaughter {
    print("My daughters name is: \(nameOfDaughter)")
}

Lub tak:

guard let nameOfDaughter = nameOfDaughter else { return }
print("My daughters name is: \(nameOfDaughter)")
[[11]}ta odpowiedź miała na celu bądź zwięzły, dla pełnego zrozumienia przeczytaj zaakceptowaną odpowiedź
 48
Author: Sajjon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-25 09:59:10

To pytanie pojawia się cały czas na tak. Jest to jedna z pierwszych rzeczy, z którymi zmagają się nowi Programiści Swift.

Background:

Swift używa pojęcia "opcji" do radzenia sobie z wartościami, które mogą zawierać wartość, lub nie. W innych językach, takich jak C, możesz zapisać wartość 0 w zmiennej, aby wskazać, że nie zawiera ona żadnej wartości. Co jednak zrobić, jeśli 0 jest poprawną wartością? Wtedy możesz użyć -1. Co jeśli -1 jest poprawną wartością? I tak dalej.

Opcje Swift pozwala skonfigurować zmienną dowolnego typu tak, aby zawierała poprawną wartość lub nie miała wartości.

Stawiasz znak zapytania po typie, gdy deklarujesz zmienną jako mean(wpisz x lub brak wartości).

Opcjonalny jest w rzeczywistości kontenerem, który zawiera albo zmienną danego typu, albo nic.

Opcja musi być "rozpakowana", aby pobrać wartość w środku.

"!"operator jest operatorem "rozpakowywania siły". "Zaufaj mi. Wiem, co robię. Gwarantuję że gdy ten kod zostanie uruchomiony, zmienna nie będzie zawierać nil."Jeśli się mylisz, rozbij się.

Jeśli naprawdę nie wiesz, co robisz, unikaj"!"Siła rozpakowywania operatora. Jest to prawdopodobnie największe źródło awarii dla początkujących programistów Swift.

Jak radzić sobie z opcjami:

Istnieje wiele innych sposobów radzenia sobie z opcjami, które są bezpieczniejsze. Oto niektóre (nie wyczerpująca lista)

Możesz użyć "opcjonalnego wiązania" lub "if let", aby powiedzieć "jeśli ta opcja zawiera wartość, Zapisz tę wartość do nowej, nieobowiązkowej zmiennej. Jeśli opcjonalne nie zawiera wartości, pomiń treść instrukcji if".

Oto przykład opcjonalnego wiązania z naszym foo opcjonalnym:

if let newFoo = foo //If let is called optional binding. {
  print("foo is not nil")
} else {
  print("foo is nil")
}

Zauważ, że zmienna, którą definiujesz, gdy używasz opcjonalnego bindowania, istnieje tylko (jest Tylko "in scope") w treści instrukcji if.

Alternatywnie można użyć instrukcji guard, która pozwala na wyjście z funkcji, jeśli zmienna jest nil:

func aFunc(foo: Int?) {
  guard let newFoo = input else { return }
  //For the rest of the function newFoo is a non-optional var
}

Oświadczenia strażnicze zostały dodane w Swift 2. Guard pozwala zachować "złotą ścieżkę" w kodzie i uniknąć stale rosnących poziomów zagnieżdżonych if, które czasami wynikają z użycia opcjonalnego wiązania "if let".

Istnieje również konstrukcja zwana "operatorem zerowym". Przyjmuje postać " optional_var ?? replacement_val". Zwraca nieobowiązkową zmienną o tym samym typie, Co dane zawarte w opcjonalnym. Jeśli opcja zawiera nil, zwraca wartość wyrażenia po"??"symbol.

Więc możesz użyć takiego kodu:

let newFoo = foo ?? "nil" // "??" is the nil coalescing operator
print("foo = \(newFoo)")

Możesz również użyć obsługi błędów try / catch lub guard, ale ogólnie jedna z powyższych technik jest czystsza.

EDIT:

Innym, nieco bardziej subtelnym elementem optionals jest " implicite unwraped optionals. Kiedy deklarujemy foo, możemy powiedzieć:

var foo: String!

W takim przypadku foo jest nadal opcjonalne, ale nie musisz go rozpakowywać, aby się do niego odwołać. Oznacza to, że każdy kiedy spróbujesz nawiązać do foo, wpadniesz, jeśli będzie zero.

Więc ten kod:

var foo: String!


let upperFoo = foo.capitalizedString

Rozbije się w odniesieniu do własności foo capitalizedString, mimo że nie rozpakowujemy foo siłą. odcisk wygląda dobrze, ale nie jest.

Dlatego chcesz być bardzo ostrożny z domyślnie rozpakowanymi opcjami. (a może nawet unikać ich całkowicie, dopóki nie masz solidnego zrozumienia optionals.)

Podsumowując: kiedy po raz pierwszy uczysz się Swift, udawaj "!"charakter nie jest częścią języka. To prawdopodobnie wpędzi cię w kłopoty.

 35
Author: Duncan C,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-11 11:40:19

Po pierwsze, powinieneś wiedzieć, co to jest wartość opcjonalna. Możesz przejść do Programu Swift

Dla szczegółów.

Po drugie, powinieneś wiedzieć, że opcjonalna wartość ma dwa statusy. Jedna jest wartością PEŁNĄ, a druga jest wartością zerową. Dlatego przed zaimplementowaniem opcjonalnej wartości, powinieneś sprawdzić, który to stan.

Możesz użyć if let ... LUB guard let ... else i tak dalej.

W inny sposób, jeśli nie chcesz sprawdzać jego stanu przed implementacją, możesz również użyć var buildingName = buildingName ?? "buildingName" zamiast tego.

 9
Author: QiunCheng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-30 07:18:28

Ponieważ powyższe odpowiedzi jasno wyjaśniają, jak bezpiecznie grać za pomocą opcji. Postaram się wyjaśnić, jakie opcje są naprawdę w swift.

Innym sposobem deklarowania zmiennej opcjonalnej jest

var i : Optional<Int>

A Typ opcjonalny to nic innego jak wyliczenie z dwoma przypadkami, tj.

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

Więc przypisanie zera do naszej zmiennej "i". Możemy zrobić var i = Optional<Int>.none lub aby przypisać wartość, przekażemy pewną wartość var i = Optional<Int>.some(28)

Według Swifta "nil" to brak wartość. I aby utworzyć instancję zainicjalizowaną nil musimy dostosować się do protokołu o nazwie ExpressibleByNilLiteral i jeśli się domyślasz, tylko Optionals dostosować się do ExpressibleByNilLiteral i dostosowywać się do innych typów jest zniechęcane.

ExpressibleByNilLiteral posiada jedną metodę o nazwie init(nilLiteral:), która inicjalizuje instace za pomocą nil. Zwykle nie będzie wywoływać tej metody i zgodnie z dokumentacją swift nie zaleca się wywoływania tej inicjalizatora bezpośrednio, ponieważ kompilator wywołuje ją za każdym razem, gdy inicjalizujesz opcjonalny Typ za pomocą nil dosłownie.

Nawet ja muszę owijać (nie zamierzony kalambur) głowę wokół opcji: D Happy Swfing All .

 8
Author: Tharzeez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-17 16:15:19

Miałem ten błąd raz, gdy próbowałem ustawić wartości wyjściowe z metody prepare for segue w następujący sposób:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let destination = segue.destination as? DestinationVC{

        if let item = sender as? DataItem{
            // This line pops up the error
            destination.nameLabel.text = item.name
        }
    }
}

Potem okazało się, że nie mogę ustawić wartości docelowych gniazd kontrolera, ponieważ kontroler nie został jeszcze załadowany lub zainicjowany.

Więc rozwiązałem to w ten sposób:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let destination = segue.destination as? DestinationVC{

        if let item = sender as? DataItem{
            // Created this method in the destination Controller to update its outlets after it's being initialized and loaded
            destination.updateView(itemData:  item)
        }
    }
}

Kontroler Przeznaczenia:

// This variable to hold the data received to update the Label text after the VIEW DID LOAD
var name = ""

// Outlets
@IBOutlet weak var nameLabel: UILabel!

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
    nameLabel.text = name
}

func updateView(itemDate: ObjectModel) {
    name = itemDate.name
}

Mam nadzieję, że ta odpowiedź pomoże komukolwiek z tym samym problemem, co znalazłem zaznaczoną odpowiedź jest świetnym źródłem do zrozumienie opcji i ich działania, ale nie rozwiązało problemu bezpośrednio.

 4
Author: Wissa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-13 14:06:00

W zasadzie próbowałeś użyć wartości nil w miejscach, gdzie Swift pozwala tylko innym osobom, "oszukując" kompilator, aby pomyślał, że tam jest wartość nil, pozwalając w ten sposób Twojej aplikacji na kompilację.

Istnieje kilka scenariuszy, które prowadzą do tego rodzaju błędu krytycznego:]}
  1. Przymusowe rozpakowywanie:

    let user = someVariable!
    

    Jeśli someVariable jest zerowy, to dostaniesz crash. Wykonując force unwrap przeniosłeś odpowiedzialność nil check z kompilatora na siebie, w zasadzie wykonując wymuszone unwrap gwarantujesz kompilatorowi, że nigdy nie będziesz miał tam wartości zerowych. I zgadnij, co się stanie, jeśli tak się stanie?

    Rozwiązanie? Użyj opcjonalnego wiązania (aka if-let), wykonaj tam przetwarzanie zmiennej:

    if user = someVariable {
        // do your stuff
    }
    
  2. Wymuszone rzuty:

    let myRectangle = someShape as! Rectangle
    

    Tutaj przez wymuszone odlewanie mówisz kompilatorowi, aby się już nie martwił, ponieważ zawsze będziesz miał Rectangle instancję. I tak długo, jak to wytrzyma, nie musisz się martwić. Problemy zaczynają się, gdy ty lub twoi koledzy od projektu rozpocznij cyrkulację wartości innych niż prostokąt.

    Rozwiązanie? Użyj opcjonalnego wiązania (aka if-let), wykonaj tam przetwarzanie zmiennej:

    if let myRectangle = someShape as? Rectangle {
        // yay, I have a rectangle
    }
    
  3. Domyślnie rozpakowane opcje. Załóżmy, że masz następującą definicję klasy:

    class User {
        var name: String!
    
        init() {
            name = "none yet"
        }
    
        func nicerName() {
            return "Mr/Ms " + name
        }
    }
    

    Teraz, jeśli nikt nie pomyli się z właściwością name ustawiając ją na nil, to działa ona zgodnie z oczekiwaniami, jednak jeśli {[11] } jest zainicjalizowana z JSON, który nie ma klucza name, to pojawia się błąd krytyczny, gdy próbuję wykorzystać posiadłość.

    Rozwiązanie? Nie używaj ich :) chyba, że masz 102% pewności, że właściwość zawsze będzie miała wartość niezerową do czasu jej użycia. Jednak w większości przypadków konwersja na opcjonalne lub nieobowiązkowe będzie działać. Uczynienie go nieobowiązkowym spowoduje również, że kompilator pomoże Ci przez podanie ścieżek kodu, które przegapiłeś, dając wartość tej właściwości

  4. Niezwiązane gniazda. Jest to szczególny przypadek scenariusza # 3. Zasadniczo ty masz jakieś zajęcia z XIB, których chcesz użyć.

    class SignInViewController: UIViewController {
    
        @IBOutlet var emailTextField: UITextField!
    }
    

    Teraz, jeśli przegapiłeś podłączenie gniazdka z edytora XIB, aplikacja zawiesi się tak szybko, jak będziesz chciał użyć gniazdka. Rozwiązanie? Upewnij się, że wszystkie gniazdka są podłączone. Lub użyj na nich operatora ?: emailTextField?.text = "[email protected]". Lub zadeklarować wyjście jako opcjonalne, choć w tym przypadku kompilator zmusi cię do rozpakowania go na całym kodzie.

  5. Wartości pochodzące z Objective-C, które nie mają nullability Przypisy Załóżmy, że mamy następującą klasę Objective-C:

    @interface User: NSObject
    @property NSString *name;
    @end
    

    Teraz, jeśli nie podano adnotacji nullability (jawnie lub poprzez NS_ASSUME_NONNULL_BEGIN/NS_ASSUME_NONNULL_END), następnie właściwość name zostanie zaimportowana w języku Swift jako String! (opcjonalne IUO-domyślnie rozpakowane). Jak tylko jakiś kod swift będzie chciał użyć tej wartości, To ulegnie awarii, w zerowych przypadkach.

    Rozwiązanie? Dodaj adnotacje nullability do kodu Objective-C. Uważaj jednak, kompilator Objective-C jest trochę permissive jeśli chodzi o nullability, możesz skończyć z zerowymi wartościami, nawet jeśli wyraźnie oznaczysz je jako nonnull.

 0
Author: Cristik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-12 22:38:02

Błąd krytyczny: nieoczekiwanie znaleziono zero podczas rozpakowywania opcjonalnej wartości

Mówi, że używasz zmiennej, której wartość nie jest inicjalizowana lub ustawiona na zero.

E. g

var tempVar: String?
print(tempVar!)

TempVar nie jest inicjowany, więc aplikacja zawiesza się w tym przypadku, więc musisz użyć

print(tempVar ?? "") 
Więcej informacji można znaleźć w sekcji opcjonalne łączenie łańcuchowe ]}
 -3
Author: CrazyPro007,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-19 14:24:50