Xcode 8 / Swift 3: «Expression de type UIViewController? est inutilisé "avertissement

230

J'ai la fonction suivante qui a été compilée proprement auparavant mais génère un avertissement avec Xcode 8.

func exitViewController()
{
    navigationController?.popViewController(animated: true)
}

"L'expression de type" UIViewController? "N'est pas utilisée".

Pourquoi dit-il cela et existe-t-il un moyen de le supprimer?

Le code s'exécute comme prévu.

Gruntcakes
la source

Réponses:

498

TL; DR

popViewController(animated:)renvoie UIViewController?, et le compilateur donne cet avertissement puisque vous ne capturez pas la valeur. La solution consiste à l'affecter à un trait de soulignement:

_ = navigationController?.popViewController(animated: true)

Swift 3 Change

Avant Swift 3, toutes les méthodes avaient un «résultat jetable» par défaut. Aucun avertissement ne se produit lorsque vous ne capturez pas ce que la méthode a renvoyé.

Afin d'indiquer au compilateur que le résultat doit être capturé, vous devez ajouter @warn_unused_resultavant la déclaration de méthode. Il serait utilisé pour les méthodes qui ont une forme mutable (ex. sortEt sortInPlace). Vous ajouteriez @warn_unused_result(mutable_variant="mutableMethodHere")pour en informer le compilateur.

Cependant, avec Swift 3, le comportement est inversé. Toutes les méthodes avertissent désormais que la valeur de retour n'est pas capturée. Si vous voulez dire au compilateur que l'avertissement n'est pas nécessaire, vous ajoutez@discardableResult avant la déclaration de méthode.

Si vous ne souhaitez pas utiliser la valeur de retour, vous devez le dire explicitement au compilateur en l'attribuant à un trait de soulignement:

_ = someMethodThatReturnsSomething()

Motivation pour l'ajouter à Swift 3:

  • Prévention d'éventuels bugs (ex. Utilisation sort pensant que cela modifie la collection)
  • Intention explicite de ne pas capturer ou de ne pas avoir besoin de capturer le résultat pour d'autres collaborateurs

L'API UIKit semble être en retard sur ce point, n'ajoutant pas @discardableResultà l'utilisation parfaitement normale (sinon plus courante) de popViewController(animated:)sans capturer la valeur de retour.

Lire la suite

tktsubota
la source
15
Ceci est (à mon avis) certainement un pas en arrière de Swift 2, surtout quand il existe des méthodes de ce genre qui, même si elles font retourner une valeur, il y a des cas d'utilisation parfaitement valables où vous ne l' utilisez pas.
Nicolas Miari
15
1. Vous n'avez pas besoin de let: vous pouvez simplement assigner à _ sans le précéder avec letou var.
rickster
1
@rickster Ne savait pas que cela va ajouter à la réponse.
tktsubota
5
2. @NicolasMiari File a bug . Il y a une annotation ( @discardableResult) pour les fonctions qui renvoient une valeur mais où l'on s'attend à ce que l'on puisse ignorer la valeur de retour. UIKit n'a tout simplement pas appliqué cette annotation à son API.
rickster
37
C'est une syntaxe horrible. Pourquoi feraient-ils ça? Beurk.
David S.
38

Quand la vie vous donne des citrons, faites une extension:

import UIKit

extension UINavigationController {
    func pop(animated: Bool) {
        _ = self.popViewController(animated: animated)
    }

    func popToRoot(animated: Bool) {
        _ = self.popToRootViewController(animated: animated)
    }
}

Notez que l'ajout de quelque chose comme @discardableResult func pop(animated: Bool) -> UIViewController?cela entraînera le même avertissement que vous essayez d'éviter.

Avec l'extension, vous pouvez maintenant écrire:

func exitViewController()
{
    navigationController?.pop(animated: true)
}

func popToTheRootOfNav() {
    navigationController?.popToRoot(animated: true)
}

Edit: Ajout de popToRoot aussi.

CodeReaper
la source
Cela devrait être la solution acceptée car c'est la solution la plus propre à ce qui est sûr d'être corrigé dans une mise à jour Xcode.
Philip Broadway du
24

Dans Swift 3, ignorer la valeur de retour d'une fonction qui a une valeur de retour déclarée entraîne un avertissement.

Une façon de désactiver cette option consiste à marquer la fonction avec l' @discardableResultattribut. Puisque vous n'avez aucun contrôle sur cette fonction, cela ne fonctionnera pas.

L'autre méthode pour se débarrasser de l'avertissement est d'attribuer la valeur à _. Cela indique au compilateur que vous savez que la méthode renvoie une valeur mais que vous ne voulez pas la conserver en mémoire.

let _ = navigationController?.popViewController(animated: true)
Matelot Seaman
la source
2
Je suppose que nous devrons nous en tenir au laid _jusqu'à ce qu'Apple mette à jour UIKit avec ce nouvel attribut.
Nicolas Miari
2
Malheureusement @discardableResultne fonctionne pas (au moins il coasse toujours avec 8b4). Friedrich Schiller aimait les pommes pourries. Probablement une question de goût :-(
qwerty_so
5

Capture d'écran 1

Bien qu'il work correctly if kept as it is lenumber of warning increases.

La solution est tout simplement replace it with underscore ( _ )si elle semble être laide.

Eg.  _ = navigationController?.popViewController(animated: true)

Capture d'écran 2

Jayprakash Dubey
la source
2

Utilisez discardableResult dans cette condition.

Selon <Swift Programming Language>, chapitre Référence du langage - Attributs.

discardableResult

Appliquez cet attribut à une déclaration de fonction ou de méthode pour supprimer l'avertissement du compilateur lorsque la fonction ou la méthode qui renvoie une valeur est appelée sans utiliser son résultat.

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Attributes.html#//apple_ref/doc/uid/TP40014097-CH35-ID347

Il existe également une démo dans <Swift Programming Language>, chapitre Language Guide - Methods.

@discardableResult
    mutating func advance(to level: Int) -> Bool {
    ...
return true
}

Parce que ce n'est pas nécessairement une erreur pour le code qui appelle la méthode advance (to :) pour ignorer la valeur de retour, cette fonction est marquée avec l'attribut @discardableResult. Pour plus d'informations sur cet attribut, voir Attributs.

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Methods.html#//apple_ref/doc/uid/TP40014097-CH15-ID234

perle noire
la source
0

Si vous voulez emprunter la voie des extensions comme la réponse de CodeReaper, vous devez utiliser @descardableResult. Cela conserve toutes les possibilités, mais fait taire l'avertissement.

import UIKit

extension UINavigationController {
    @discardableResult func pop(animated: Bool) -> UIViewController? {
        return self.popViewController(animated: animated)
    }

    @discardableResult func popToRoot(animated: Bool) -> [UIViewController]? {
        return self.popToRootViewController(animated: animated)
    }
}
Casper Zandbergen
la source
-1

Vous pouvez également déballer la self.navigationController?valeur et appeler la popViewControllerfonction.

    if let navigationController = navigationController {
        navigationController.popViewController(animated: true)
    }
muazhud
la source