Xcode 8 / Swift 3: “Espressione di tipo UIViewController? è inutilizzato "avviso


230

Ho la seguente funzione che è stata compilata in modo pulito in precedenza ma genera un avviso con Xcode 8.

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

"L'espressione di tipo" UIViewController? "Non è utilizzata".

Perché sta dicendo questo e c'è un modo per rimuoverlo?

Il codice viene eseguito come previsto.

Risposte:


498

TL; DR

popViewController(animated:)ritorna UIViewController?e il compilatore sta dando quell'avvertimento poiché non stai acquisendo il valore. La soluzione è assegnarlo a un carattere di sottolineatura:

_ = navigationController?.popViewController(animated: true)

Swift 3 Change

Prima di Swift 3, tutti i metodi avevano un "risultato scartabile" per impostazione predefinita. Non si verificherebbe alcun avviso se non è stato acquisito il metodo restituito.

Per dire al compilatore che il risultato deve essere acquisito, è necessario aggiungere @warn_unused_resultprima della dichiarazione del metodo. Sarebbe usato per metodi che hanno una forma mutabile (es. sortE sortInPlace). Aggiungeresti @warn_unused_result(mutable_variant="mutableMethodHere")per dirlo al compilatore.

Tuttavia, con Swift 3, il comportamento viene invertito. Tutti i metodi ora avvisano che il valore restituito non viene acquisito. Se vuoi dire al compilatore che l'avviso non è necessario, aggiungi @discardableResultprima della dichiarazione del metodo.

Se non si desidera utilizzare il valore restituito, è necessario indicare esplicitamente al compilatore assegnandolo a un carattere di sottolineatura:

_ = someMethodThatReturnsSomething()

Motivazione per l'aggiunta di questo a Swift 3:

  • Prevenzione di possibili bug (es. Usando il sortpensiero modifica la raccolta)
  • Intenzione esplicita di non acquisire o necessità di acquisire il risultato per altri collaboratori

L'API UIKit sembra essere indietro su questo, non aggiungendo @discardableResultper l'uso perfettamente normale (se non più comune) popViewController(animated:)senza acquisire il valore di ritorno.

Leggi di più


15
Questo è (a mio parere) decisamente un passo indietro da Swift 2, soprattutto quando ci sono metodi come questo che, anche se fanno restituire un valore, ci sono casi di utilizzo perfettamente valide in cui proprio non ne fanno uso.
Nicolas Miari,

15
1. Non hai bisogno di let: puoi semplicemente assegnare a _ senza precederlo con leto var.
rickster,

1
@Rickster Non sapevo che aggiungerà per rispondere.
tktsubota,

5
2. @NicolasMiari File a bug . C'è un'annotazione ( @discardableResult) per le funzioni che restituiscono un valore ma in cui è previsto che si possa ignorare il valore restituito. UIKit non ha applicato questa annotazione alla sua API.
rickster,

37
Questa è una sintassi orribile. Perché dovrebbero farlo? Che schifo.
David S.

38

Quando la vita ti dà limoni, fai un'estensione:

import UIKit

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

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

Nota che l'aggiunta di qualcosa del genere @discardableResult func pop(animated: Bool) -> UIViewController?comporterà lo stesso avviso che stai cercando di evitare.

Con l'estensione ora puoi scrivere:

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

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

Modifica: aggiunto anche popToRoot.


Questa dovrebbe essere la soluzione accettata poiché è la soluzione più pulita a ciò che è sicuro di essere risolto in un aggiornamento Xcode.
Philip Broadway,

24

In Swift 3, ignorando il valore di ritorno di una funzione che ha un valore di ritorno dichiarato si ottiene un avviso.

Un modo per annullare questa opzione è contrassegnare la funzione con l' @discardableResultattributo. Dal momento che non hai il controllo su questa funzione, non funzionerà.

L'altro metodo per eliminare l'avviso è assegnare il valore a _. Questo dice al compilatore che sai che il metodo restituisce un valore ma non vuoi mantenerlo in memoria.

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

2
Immagino che dovremo restare con i brutti _finché Apple non aggiorna UIKit con questo nuovo attributo.
Nicolas Miari,

2
Sfortunatamente @discardableResultnon funziona (almeno grida ancora con 8b4). Friedrich Schiller adorava le mele marce. Probabilmente una questione di gusti :-(
qwerty_so

5

Schermata 1

Anche se work correctly if kept as it isma ilnumber of warning increases.

La soluzione è semplicemente replace it with underscore ( _ )se sembra essere brutto.

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

Schermata 2


2

Utilizzare discardableResult in questa condizione.

Secondo <Swift Programming Language>, capitolo Riferimenti linguistici - Attributi.

discardableResult

Applicare questo attributo a una dichiarazione di funzione o metodo per sopprimere l'avviso del compilatore quando viene chiamata la funzione o il metodo che restituisce un valore senza utilizzare il suo risultato.

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

C'è anche una demo in <Swift Programming Language>, capitolo Guida linguistica - Metodi.

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

Poiché non è necessariamente un errore per il codice che chiama il metodo anticipo (a :) per ignorare il valore restituito, questa funzione è contrassegnata con l'attributo @discardableResult. Per ulteriori informazioni su questo attributo, consultare Attributi.

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


0

Se vuoi andare sulla strada delle estensioni come la risposta di CodeReaper, dovresti usare @descardableResult. Ciò mantiene tutte le possibilità, ma mette a tacere l'avvertimento.

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

-1

Un altro modo è di scartare il self.navigationController?valore e chiamare la popViewControllerfunzione.

    if let navigationController = navigationController {
        navigationController.popViewController(animated: true)
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.