Que signifie "Erreur fatale: néant inopinément trouvé lors du déballage d'une valeur facultative"?

Aug 24 2015

Mon programme Swift plante avec l' EXC_BAD_INSTRUCTIONune des erreurs similaires suivantes. Que signifie cette erreur et comment la corriger?

Erreur fatale: nul trouvé de manière inattendue lors du déballage d'une valeur facultative

ou

Erreur fatale: trouvé nul de manière inattendue lors du déballage implicite d'une valeur facultative


Cet article est destiné à collecter des réponses aux problèmes «inopinément trouvés nil», afin qu'ils ne soient pas dispersés et difficiles à trouver. N'hésitez pas à ajouter votre propre réponse ou à modifier la réponse wiki existante.

Réponses

685 Hamish Aug 24 2015 at 02:10

Cette réponse est le wiki de la communauté . Si vous pensez qu'il pourrait être amélioré, n'hésitez pas à le modifier !

Contexte: Qu'est-ce qu'une option?

Dans Swift, Optional<Wrapped>est un type d'option : il peut contenir n'importe quelle valeur du type original ("Wrapped"), ou aucune valeur du tout (la valeur spéciale nil). Une valeur facultative doit être déballée avant de pouvoir être utilisée.

Facultatif est un type générique , ce qui signifie que Optional<Int>et Optional<String>sont des types distincts - le type à l'intérieur <>est appelé le type Wrapped. Sous le capot, une option est une énumération avec deux cas: .some(Wrapped)et .none, où .noneest équivalent à nil.

Les options peuvent être déclarées en utilisant le type nommé Optional<T>, ou (le plus souvent) comme un raccourci avec un ?suffixe.

var anInt: Int = 42
var anOptionalInt: Int? = 42
var anotherOptionalInt: Int?  // `nil` is the default when no value is provided
var aVerboseOptionalInt: Optional<Int>  // equivalent to `Int?`

anOptionalInt = nil // now this variable contains nil instead of an integer

Les options sont un outil simple mais puissant pour exprimer vos hypothèses lors de l'écriture de code. Le compilateur peut utiliser ces informations pour vous éviter de faire des erreurs. À partir du langage de programmation Swift :

Swift est un langage de type sécurisé , ce qui signifie que le langage vous aide à être clair sur les types de valeurs avec lesquels votre code peut fonctionner. Si une partie de votre code nécessite une String, la sécurité de type vous empêche de la transmettre Intpar erreur. De même, la sécurité de type vous empêche de passer accidentellement un optionnel Stringà un morceau de code qui nécessite un non-optionnel String. La sécurité des types vous aide à détecter et à corriger les erreurs le plus tôt possible dans le processus de développement.

Certains autres langages de programmation ont également des types d'options génériques : par exemple, Peut - être dans Haskell, option dans Rust et facultatif dans C ++ 17.

Dans les langages de programmation sans types d'option, une valeur "sentinelle" particulière est souvent utilisée pour indiquer l'absence d'une valeur valide. En Objective-C, par exemple, nil(le pointeur nul ) représente l'absence d'un objet. Pour les types primitifs tels que int, un pointeur nul ne peut pas être utilisé, vous auriez donc besoin d'une variable distincte (telle que value: Intet isValid: Bool) ou d'une valeur sentinelle désignée (telle que -1ou INT_MIN). Ces approches sont sujettes aux erreurs car il est facile d'oublier de vérifier isValidou de vérifier la valeur sentinelle. De plus, si une valeur particulière est choisie comme sentinelle, cela signifie qu'elle ne peut plus être traitée comme une valeur valide .

Les types d'options tels que ceux de Swift Optionalrésolvent ces problèmes en introduisant une nilvaleur spéciale et distincte (pour que vous n'ayez pas à désigner une valeur sentinelle), et en tirant parti du système de type fort pour que le compilateur puisse vous aider à vous rappeler de vérifier la valeur nulle si nécessaire.


Pourquoi ai-je reçu " erreur fatale: inopinément trouvé nul lors du déballage d'une valeur facultative "?

Pour accéder à la valeur d'une option (si elle en a une), vous devez la déballer . Une valeur facultative peut être déballée en toute sécurité ou de force. Si vous forcez le déballage d'un optionnel et qu'il n'a pas de valeur, votre programme plantera avec le message ci-dessus.

Xcode vous montrera le crash en mettant en évidence une ligne de code. Le problème se produit sur cette ligne.

Ce crash peut se produire avec deux types de dépliage forcé:

1. Déballage forcé explicite

Cela se fait avec l' !opérateur sur une option. Par exemple:

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

Erreur fatale: nul trouvé de manière inattendue lors du déballage d'une valeur facultative

Comme anOptionalStringest nilici, vous obtiendrez un accident sur la ligne où vous forcez le déballer.

2. Options optionnelles implicitement non emballées

Celles-ci sont définies par un !, plutôt que par un ?après le type.

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

Ces options sont supposées contenir une valeur. Par conséquent, chaque fois que vous accédez à une option non emballée implicitement, elle sera automatiquement déballée de force pour vous. S'il ne contient pas de valeur, il plantera.

print(optionalDouble) // <- CRASH

Erreur fatale: trouvé nul de manière inattendue lors du déballage implicite d' une valeur facultative

Afin de déterminer quelle variable a causé le plantage, vous pouvez maintenir en cliquant pour afficher la définition, où vous pouvez trouver le type facultatif.

Les IBOutlets, en particulier, sont généralement des options implicitement déroulées. C'est parce que votre xib ou votre storyboard reliera les prises au moment de l'exécution, après l' initialisation. Vous devez donc vous assurer que vous n'accédez pas aux prises avant leur chargement. Vous devez également vérifier que les connexions sont correctes dans votre fichier storyboard / xib, sinon les valeurs seront nilau moment de l'exécution, et donc plantent lorsqu'elles sont implicitement déballées . Lors de la fixation des connexions, essayez de supprimer les lignes de code qui définissent vos prises, puis reconnectez-les.


Quand devrais-je forcer le déballage d'une option?

Déballage de force explicite

En règle générale, vous ne devez jamais forcer explicitement le déballage d'un optionnel avec l' !opérateur. Il peut y avoir des cas où l'utilisation !est acceptable - mais vous ne devriez l'utiliser que si vous êtes sûr à 100% que l'option contient une valeur.

Bien qu'il puisse y avoir une occasion où vous pouvez utiliser le déballage forcé, comme vous le savez pour un fait qu'un optionnel contient une valeur - il n'y a pas un seul endroit où vous ne pouvez pas dérouler en toute sécurité cet optionnel à la place.

Options optionnelles implicitement non emballées

Ces variables sont conçues pour que vous puissiez reporter leur affectation à plus tard dans votre code. Il est de votre responsabilité de vous assurer qu'ils ont une valeur avant d'y accéder. Cependant, comme ils impliquent un déballage forcé, ils sont toujours intrinsèquement dangereux - car ils supposent que votre valeur est non-nulle, même si l'attribution de zéro est valide.

Vous ne devriez utiliser que des options implicitement non emballées en dernier recours . Si vous pouvez utiliser une variable différée , ou fournir une valeur par défaut pour une variable, vous devriez le faire au lieu d'utiliser un optionnel implicitement déroulé.

Cependant, il existe quelques scénarios où les options implicitement déballées sont bénéfiques , et vous pouvez toujours utiliser différentes manières de les déballer en toute sécurité, comme indiqué ci-dessous - mais vous devez toujours les utiliser avec prudence.


Comment puis-je traiter en toute sécurité les options?

Le moyen le plus simple de vérifier si un optionnel contient une valeur est de le comparer à nil.

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

Cependant, 99,9% du temps lorsque vous travaillez avec des options, vous voudrez en fait accéder à la valeur qu'elle contient, si elle en contient une. Pour ce faire, vous pouvez utiliser la liaison facultative .

Reliure facultative

La liaison facultative vous permet de vérifier si une option contient une valeur - et vous permet d'attribuer la valeur non emballée à une nouvelle variable ou constante. Il utilise la syntaxe if let x = anOptional {...}ou if var x = anOptional {...}, selon si vous devez modifier la valeur de la nouvelle variable après la liaison.

Par exemple:

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

Cela fait d'abord vérifier que l'option contient une valeur. Si c'est le cas , alors la valeur «non emballée» est affectée à une nouvelle variable ( number) - que vous pouvez ensuite utiliser librement comme si elle n'était pas facultative. Si l'option facultative ne contient pas de valeur, la clause else sera invoquée, comme vous vous en doutez.

Ce qui est bien avec la liaison facultative, c'est que vous pouvez déplier plusieurs options en même temps. Vous pouvez simplement séparer les instructions par une virgule. L'instruction réussira si toutes les options ont été déballées.

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")
}

Une autre astuce intéressante est que vous pouvez également utiliser des virgules pour vérifier une certaine condition sur la valeur, après l'avoir déballée.

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

Le seul problème avec l'utilisation de la liaison facultative dans une instruction if, est que vous ne pouvez accéder à la valeur déballée qu'à partir de la portée de l'instruction. Si vous avez besoin d'accéder à la valeur en dehors de la portée de l'instruction, vous pouvez utiliser une instruction de garde .

Une instruction de garde vous permet de définir une condition de succès - et la portée actuelle ne continuera à s'exécuter que si cette condition est remplie. Ils sont définis avec la syntaxe guard condition else {...}.

Donc, pour les utiliser avec une liaison facultative, vous pouvez le faire:

guard let number = anOptionalInt else {
    return
}

(Notez que dans le corps de garde, vous devez utiliser l'une des instructions de transfert de contrôle afin de quitter la portée du code en cours d'exécution).

Si anOptionalIntcontient une valeur, elle sera déroulée et affectée à la nouvelle numberconstante. Le code après la garde continuera alors à s'exécuter. S'il ne contient pas de valeur, le gardien exécutera le code entre crochets, ce qui entraînera un transfert de contrôle, de sorte que le code immédiatement après ne sera pas exécuté.

La vraie chose intéressante à propos des instructions de garde est que la valeur non emballée est maintenant disponible pour être utilisée dans le code qui suit l'instruction (car nous savons que le futur code ne peut s'exécuter que si l'option facultative a une valeur). C'est un excellent moyen d'éliminer les «pyramides de malheur» créées en imbriquant plusieurs instructions if.

Par exemple:

guard let number = anOptionalInt else {
    return
}

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

Les gardes prennent également en charge les mêmes astuces intéressantes que l'instruction if prise en charge, telles que le déballage de plusieurs options en même temps et l'utilisation de la whereclause.

Le fait que vous utilisiez une instruction if ou guard dépend complètement de la question de savoir si un code futur nécessite que l'option facultative contienne une valeur.

Nil Opérateur de coalescence

L' opérateur de coalescence Nil est une version abrégée astucieuse de l' opérateur conditionnel ternaire , principalement conçu pour convertir les options en non-option. Il a la syntaxe a ?? b, où aest un type facultatif et best du même type que a(bien que généralement non facultatif).

Il vous permet essentiellement de dire «Si acontient une valeur, dépliez-la. Si ce n'est pas le cas, revenez à la bplace ». Par exemple, vous pouvez l'utiliser comme ceci:

let number = anOptionalInt ?? 0

Cela définira une numberconstante de Inttype, qui contiendra soit la valeur de anOptionalInt, si elle contient une valeur, soit 0autre.

C'est juste un raccourci pour:

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

Chaînage facultatif

Vous pouvez utiliser le chaînage facultatif pour appeler une méthode ou accéder à une propriété sur un fichier facultatif. Cela se fait simplement en ajoutant au nom de la variable un suffixe ?lors de son utilisation.

Par exemple, disons que nous avons une variable foo, de type une Fooinstance facultative .

var foo : Foo?

Si nous voulions appeler une méthode fooqui ne retourne rien, nous pouvons simplement faire:

foo?.doSomethingInteresting()

Si foocontient une valeur, cette méthode sera appelée dessus. Si ce n'est pas le cas, rien de grave ne se passera - le code continuera simplement à s'exécuter.

(Il s'agit d'un comportement similaire à l'envoi de messages nilen Objective-C)

Cela peut donc également être utilisé pour définir des propriétés ainsi que des méthodes d'appel. Par exemple:

foo?.bar = Bar()

Encore une fois, rien de mauvais ne se passera ici si fooc'est le cas nil. Votre code continuera simplement à s'exécuter.

Une autre astuce intéressante que le chaînage facultatif vous permet de faire est de vérifier si la définition d'une propriété ou l'appel d'une méthode a réussi. Vous pouvez le faire en comparant la valeur de retour à nil.

(C'est parce qu'une valeur optionnelle retournera Void?plutôt que Voidsur une méthode qui ne renvoie rien)

Par exemple:

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

Cependant, les choses deviennent un peu plus délicates lorsque vous essayez d'accéder à des propriétés ou d'appeler des méthodes qui renvoient une valeur. Parce que fooc'est facultatif, tout ce qui en retourne sera également facultatif. Pour gérer cela, vous pouvez soit dérouler les options qui sont renvoyées en utilisant l'une des méthodes ci-dessus, soit se dérouler fooavant d'accéder aux méthodes ou d'appeler des méthodes qui renvoient des valeurs.

De plus, comme son nom l'indique, vous pouvez «enchaîner» ces déclarations. Cela signifie que si fooa une propriété facultative baz, qui a une propriété qux- vous pouvez écrire ce qui suit:

let optionalQux = foo?.baz?.qux

Encore une fois, étant donné que fooet bazsont facultatifs, la valeur renvoyée par quxsera toujours une option, qu'elle soit quxelle-même facultative ou non.

map et flatMap

Une fonctionnalité souvent sous-utilisée avec les options est la possibilité d'utiliser les fonctions mapet flatMap. Celles-ci vous permettent d'appliquer des transformations non facultatives à des variables facultatives. Si un optionnel a une valeur, vous pouvez lui appliquer une transformation donnée. S'il n'a pas de valeur, il restera nil.

Par exemple, disons que vous avez une chaîne facultative:

let anOptionalString:String?

En lui appliquant la mapfonction - nous pouvons utiliser la stringByAppendingStringfonction afin de la concaténer à une autre chaîne.

Étant donné que stringByAppendingStringprend un argument de chaîne non facultatif, nous ne pouvons pas saisir directement notre chaîne facultative. Cependant, en utilisant map, nous pouvons utiliser allow stringByAppendingStringto be used if anOptionalStringhas a value.

Par exemple:

var anOptionalString:String? = "bar"

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

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

Cependant, si anOptionalStringn'a pas de valeur, mapretournera nil. Par exemple:

var anOptionalString:String?

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

print(anOptionalString) // nil

flatMapfonctionne de la même manière que map, sauf qu'il vous permet de renvoyer une autre option à partir du corps de fermeture. Cela signifie que vous pouvez entrer une option dans un processus qui nécessite une entrée non facultative, mais qui peut générer une option elle-même.

try!

Le système de gestion des erreurs de Swift peut être utilisé en toute sécurité avec Do-Try-Catch :

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

Si someThrowingFunc()génère une erreur, l'erreur sera interceptée en toute sécurité dans le catchbloc.

La errorconstante que vous voyez dans le catchbloc n'a pas été déclarée par nous - elle est automatiquement générée par catch.

Vous pouvez également errorvous déclarer , il a l'avantage de pouvoir le caster dans un format utile, par exemple:

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

L'utilisation de trycette méthode est la bonne façon d'essayer, d'attraper et de gérer les erreurs provenant des fonctions de lancement.

Il y a aussi try?ce qui absorbe l'erreur:

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

Mais le système de gestion des erreurs de Swift fournit également un moyen de "forcer l'essai" avec try!:

let result = try! someThrowingFunc()

Les concepts expliqués dans cet article s'appliquent également ici: si une erreur est levée, l'application plantera.

Vous ne devriez jamais l'utiliser que try!si vous pouvez prouver que son résultat n'échouera jamais dans votre contexte - et c'est très rare.

La plupart du temps, vous utiliserez le système Do-Try-Catch complet - et celui en option try?, dans les rares cas où la gestion de l'erreur n'est pas importante.


Ressources

65 Sajjon Dec 19 2016 at 20:26

Réponse TL; DR

À de très rares exceptions près , cette règle est d'or:

Évitez d'utiliser !

Déclarez la variable optionnelle ( ?), non les options implicitement non déroulées (IUO) ( !)

En d'autres termes, utilisez plutôt:
var nameOfDaughter: String?

Au lieu de:
var nameOfDaughter: String!

Développer la variable facultative à l'aide de if letouguard let

Soit une variable dépliée comme celle-ci:

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

Ou comme ça:

guard let nameOfDaughter = nameOfDaughter else { return }
print("My daughters name is: \(nameOfDaughter)")

Cette réponse était destinée à être concise, pour une compréhension complète lire la réponse acceptée


Ressources

40 DuncanC Feb 28 2016 at 21:37

Cette question revient TOUT LE TEMPS sur SO. C'est l'une des premières choses avec lesquelles les nouveaux développeurs Swift ont du mal.

Contexte:

Swift utilise le concept de "Optionals" pour traiter des valeurs qui pourraient contenir une valeur, ou non. Dans d'autres langages comme C, vous pouvez stocker une valeur de 0 dans une variable pour indiquer qu'elle ne contient aucune valeur. Cependant, que faire si 0 est une valeur valide? Ensuite, vous pouvez utiliser -1. Et si -1 est une valeur valide? Etc.

Les options Swift vous permettent de configurer une variable de n'importe quel type pour qu'elle contienne soit une valeur valide, soit aucune valeur.

Vous mettez un point d'interrogation après le type lorsque vous déclarez une variable à signifier (type x, ou aucune valeur).

Un optionnel est en fait un conteneur qui contient soit une variable d'un type donné, soit rien.

Un optionnel doit être "déballé" afin de récupérer la valeur à l'intérieur.

Le "!" L'opérateur est un opérateur de "déroulement forcé". Il dit "faites-moi confiance. Je sais ce que je fais. Je vous garantis que lorsque ce code s'exécutera, la variable ne contiendra pas nil." Si vous vous trompez, vous vous écrasez.

À moins que vous ne sachiez vraiment ce que vous faites, évitez le "!" forcer l'opérateur à déballer. C'est probablement la plus grande source de plantages pour les programmeurs Swift débutants.

Comment gérer les options:

Il existe de nombreuses autres façons de traiter les options qui sont plus sûres. En voici quelques-uns (liste non exhaustive)

Vous pouvez utiliser "liaison facultative" ou "if let" pour dire "si cette option contient une valeur, enregistrez cette valeur dans une nouvelle variable non facultative. Si l'option facultative ne contient pas de valeur, ignorez le corps de cette instruction if ".

Voici un exemple de liaison facultative avec notre foooption:

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

Notez que la variable que vous définissez lorsque vous utilisez l'option de soumission optionnelle n'existe que (est uniquement "dans la portée") dans le corps de l'instruction if.

Alternativement, vous pouvez utiliser une instruction de garde, qui vous permet de quitter votre fonction si la variable est nulle:

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

Des instructions Guard ont été ajoutées dans Swift 2. Guard vous permet de conserver le "chemin d'or" à travers votre code, et d'éviter les niveaux toujours croissants de if imbriqués qui résultent parfois de l'utilisation de la liaison optionnelle "if let".

Il existe également une construction appelée "opérateur de fusion nil". Il prend la forme "facultatif_var ?? replacement_val". Il renvoie une variable non facultative du même type que les données contenues dans l'option. Si l'option contient nil, elle renvoie la valeur de l'expression après le "??" symbole.

Vous pouvez donc utiliser un code comme celui-ci:

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

Vous pouvez également utiliser la gestion des erreurs try / catch ou guard, mais généralement l'une des autres techniques ci-dessus est plus propre.

ÉDITER:

Un autre piège un peu plus subtil avec les options est "les options implicitement non emballées. Lorsque nous déclarons foo, nous pourrions dire:

var foo: String!

Dans ce cas, foo est toujours facultatif, mais vous n'avez pas à le dérouler pour le référencer. Cela signifie que chaque fois que vous essayez de référencer foo, vous plantez si c'est nul.

Donc ce code:

var foo: String!


let upperFoo = foo.capitalizedString

Va planter sur la référence à la propriété capitalizedString de foo même si nous ne forçons pas le déballage de foo. l'impression a l'air bien, mais ce n'est pas le cas.

Ainsi, vous voulez être très prudent avec les options implicitement non emballées. (et peut-être même les éviter complètement jusqu'à ce que vous ayez une solide compréhension des options.)

Bottom line: Lorsque vous apprenez Swift pour la première fois, faites comme si le "!" le caractère ne fait pas partie de la langue. Cela risque de vous causer des ennuis.

13 Tharzeez Nov 17 2017 at 23:15

Puisque les réponses ci-dessus expliquent clairement comment jouer en toute sécurité avec les options. Je vais essayer d'expliquer quelles options sont vraiment rapides.

Une autre façon de déclarer une variable facultative est

var i : Optional<Int>

Et le type facultatif n'est rien d'autre qu'une énumération avec deux cas, c'est-à-dire

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

Donc, pour affecter un nul à notre variable 'i'. On peut faire var i = Optional<Int>.none ou assigner une valeur, on va passer une certaine valeur var i = Optional<Int>.some(28)

Selon Swift, «nul» est l'absence de valeur. Et pour créer une instance initialisée avec nilNous devons nous conformer à un protocole appelé ExpressibleByNilLiteralet excellent si vous l'avez deviné, il est déconseillé de se Optionalsconformer ExpressibleByNilLiteralet de se conformer aux autres types.

ExpressibleByNilLiterala une seule méthode appelée init(nilLiteral:)qui initialise un instace avec nil. Vous n'appelerez généralement pas cette méthode et selon la documentation rapide, il est déconseillé d'appeler cet initialiseur directement car le compilateur l'appelle chaque fois que vous initialisez un type facultatif avec un nillittéral.

Même moi-même doit envelopper (sans jeu de mots) ma tête autour d' options : D Happy Swfting All .

12 QiunCheng Jul 30 2016 at 14:18

Tout d'abord, vous devez savoir ce qu'est une valeur facultative. Vous pouvez accéder au langage de programmation Swift pour plus de détails.

Deuxièmement, vous devez savoir que la valeur facultative a deux statuts. L'un est la valeur complète et l'autre est une valeur nulle. Donc, avant d'implémenter une valeur facultative, vous devez vérifier de quel état il s'agit.

Vous pouvez utiliser if let ...ou guard let ... elseet ainsi de suite.

Une autre façon, si vous ne souhaitez pas vérifier l'état de la variable avant votre implémentation, vous pouvez également utiliser à la var buildingName = buildingName ?? "buildingName"place.

8 Wissa Apr 13 2018 at 21:06

J'ai eu cette erreur une fois lorsque j'essayais de définir les valeurs de mes points de vente à partir de la méthode prepare for segue comme suit:

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
        }
    }
}

Ensuite, j'ai découvert que je ne pouvais pas définir les valeurs des sorties du contrôleur de destination car le contrôleur n'avait pas encore été chargé ou initialisé.

Alors je l'ai résolu de cette façon:

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)
        }
    }
}

Contrôleur de destination:

// 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
}

J'espère que cette réponse aidera quiconque a le même problème car j'ai trouvé que la réponse marquée est une excellente ressource pour la compréhension des options et de leur fonctionnement, mais n'a pas abordé le problème lui-même directement.

7 Cristik Sep 19 2018 at 13:04

En gros, vous avez essayé d'utiliser une valeur nulle dans les endroits où Swift n'autorise que des valeurs non nulles, en disant au compilateur de vous faire confiance qu'il n'y aura jamais de valeur nulle, permettant ainsi à votre application de se compiler.

Il existe plusieurs scénarios qui conduisent à ce type d'erreur fatale:

  1. déballage forcé:

    let user = someVariable!
    

    Si someVariablec'est nul, alors vous aurez un crash. En effectuant un déballage forcé, vous avez déplacé la responsabilité de vérification nil du compilateur vers vous, essentiellement en effectuant un déballage forcé, vous garantissez au compilateur que vous n'aurez jamais de valeurs nulles. Et devinez ce qu'il se passe si d'une manière ou d'une autre une valeur nulle se termine someVariable?

    Solution? Utilisez une liaison facultative (aka if-let), faites le traitement des variables ici:

    if user = someVariable {
        // do your stuff
    }
    
  2. lancers forcés (vers le bas):

    let myRectangle = someShape as! Rectangle
    

    Ici, par la conversion forcée, vous dites au compilateur de ne plus s'inquiéter, car vous y trouverez toujours une Rectangleinstance. Et tant que cela tient, vous n'avez pas à vous inquiéter. Les problèmes commencent lorsque vous ou vos collègues du projet commencez à faire circuler des valeurs non rectangulaires.

    Solution? Utilisez une liaison facultative (aka if-let), faites le traitement des variables ici:

    if let myRectangle = someShape as? Rectangle {
        // yay, I have a rectangle
    }
    
  3. Options optionnelles implicitement déroulées. Supposons que vous ayez la définition de classe suivante:

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

    Maintenant, si personne ne gâche la namepropriété en la définissant sur nil, cela fonctionne comme prévu, mais si Userest initialisé à partir d'un JSON qui n'a pas la nameclé, vous obtenez l'erreur fatale lorsque vous essayez d'utiliser la propriété.

    Solution? Ne les utilisez pas :) Sauf si vous êtes sûr à 102% que la propriété aura toujours une valeur non nulle au moment où elle doit être utilisée. Dans la plupart des cas, la conversion en option ou non fonctionnera. En le rendant non facultatif, le compilateur vous aidera également en indiquant les chemins de code que vous avez manqués en donnant une valeur à cette propriété

  4. Prises non connectées ou pas encore connectées. C'est un cas particulier du scénario n ° 3. En gros, vous avez une classe chargée XIB que vous souhaitez utiliser.

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

    Maintenant, si vous avez manqué de connecter la prise à partir de l'éditeur XIB, l'application se bloquera dès que vous voudrez utiliser la prise. Solution? Assurez-vous que toutes les prises sont connectées. Ou utilisez l' ?opérateur sur eux emailTextField?.text = "[email protected]". Ou déclarez la sortie comme facultative, bien que dans ce cas, le compilateur vous obligera à la déballer dans tout le code.

  5. Valeurs provenant d'Objective-C, et qui n'ont pas d'annotations de nullabilité. Supposons que nous ayons la classe Objective-C suivante:

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

    Désormais, si aucune annotation de nullabilité n'est spécifiée (soit explicitement, soit via NS_ASSUME_NONNULL_BEGIN/ NS_ASSUME_NONNULL_END), la namepropriété sera importée dans Swift en tant que String!(un IUO - implicitement déroulé en option). Dès qu'un code swift voudra utiliser la valeur, il plantera si elle nameest nulle.

    Solution? Ajoutez des annotations de nullité à votre code Objective-C. Attention cependant, le compilateur Objective-C est un peu permissif en ce qui concerne la nullité, vous pouvez vous retrouver avec des valeurs nulles, même si vous les avez explicitement marquées comme nonnull.

2 Honey Nov 01 2018 at 11:39

C'est plus un commentaire important et c'est pourquoi les options implicitement non emballées peuvent être trompeuses lorsqu'il s'agit de déboguer les nilvaleurs.

Pensez au code suivant: Il se compile sans erreurs / avertissements:

c1.address.city = c3.address.city

Pourtant, au moment de l'exécution, il donne l'erreur suivante: Erreur fatale: trouvé nul de manière inattendue lors du déballage d'une valeur facultative

Pouvez-vous me dire quel est l'objet nil?

Vous ne pouvez pas!

Le code complet serait:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        var c1 = NormalContact()
        let c3 = BadContact()

        c1.address.city = c3.address.city // compiler hides the truth from you and then you sudden get a crash
    }
}

struct NormalContact {
    var address : Address = Address(city: "defaultCity")
}

struct BadContact {
    var address : Address!
}

struct Address {
    var city : String
}

En bref, en utilisant var address : Address!vous cachez la possibilité qu'une variable puisse provenir nild'autres lecteurs. Et quand il plante, vous vous dites "que diable?! Mon addressn'est pas facultatif, alors pourquoi est-ce que je plante?!.

Il est donc préférable d'écrire comme tel:

c1.address.city = c2.address!.city  // ERROR:  Fatal error: Unexpectedly found nil while unwrapping an Optional value 

Pouvez-vous maintenant me dire de quel objet il s'agissait nil?

Cette fois, le code vous a été rendu plus clair. Vous pouvez rationaliser et penser que c'est probablement le addressparamètre qui a été déballé avec force.

Le code complet serait:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        var c1 = NormalContact()
        let c2 = GoodContact()

        c1.address.city = c2.address!.city
        c1.address.city = c2.address?.city // not compile-able. No deceiving by the compiler
        c1.address.city = c2.address.city // not compile-able. No deceiving by the compiler
        if let city = c2.address?.city {  // safest approach. But that's not what I'm talking about here. 
            c1.address.city = city
        }

    }
}

struct NormalContact {
    var address : Address = Address(city: "defaultCity")
}

struct GoodContact {
    var address : Address?
}

struct Address {
    var city : String
}
2 AleMohamad May 21 2019 at 00:34

Les erreurs EXC_BAD_INSTRUCTIONet fatal error: unexpectedly found nil while implicitly unwrapping an Optional valueapparaissent le plus lorsque vous avez déclaré un @IBOutlet, mais pas connecté au storyboard .

Vous devriez également en savoir plus sur le fonctionnement des options , mentionné dans d'autres réponses, mais c'est le seul moment qui me semble le plus souvent.

2 ShigaSuresh Feb 13 2020 at 01:16

Si vous obtenez cette erreur dans CollectionView, essayez également de créer un fichier CustomCell et un fichier xib personnalisé.

ajoutez ce code dans ViewDidLoad () à mainVC.

    let nib = UINib(nibName: "CustomnibName", bundle: nil)
    self.collectionView.register(nib, forCellWithReuseIdentifier: "cell")
MikeVolmar Sep 26 2019 at 22:11

Je suis tombé sur cette erreur en effectuant une transition d'un contrôleur de vue de table vers un contrôleur de vue car j'avais oublié de spécifier le nom de classe personnalisé pour le contrôleur de vue dans le storyboard principal.

Quelque chose de simple qui vaut la peine de vérifier si tout le reste va bien