Xcode 8 / Swift 3: „Ausdruck vom Typ UIViewController? wird nicht verwendet “Warnung

230

Ich habe die folgende Funktion, die zuvor sauber kompiliert wurde, aber mit Xcode 8 eine Warnung generiert.

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

"Ausdruck vom Typ" UIViewController? "Wird nicht verwendet".

Warum sagt es das und gibt es eine Möglichkeit, es zu entfernen?

Der Code wird wie erwartet ausgeführt.

Gruntcakes
quelle

Antworten:

498

TL; DR

popViewController(animated:)kehrt zurück UIViewController?, und der Compiler gibt diese Warnung aus, da Sie den Wert nicht erfassen. Die Lösung besteht darin, es einem Unterstrich zuzuweisen:

_ = navigationController?.popViewController(animated: true)

Swift 3 Change

Vor Swift 3 hatten alle Methoden standardmäßig ein "verwertbares Ergebnis". Es wird keine Warnung angezeigt, wenn Sie nicht erfasst haben, was die Methode zurückgegeben hat.

Um dem Compiler mitzuteilen, dass das Ergebnis erfasst werden soll, mussten Sie @warn_unused_resultvor der Methodendeklaration hinzufügen . Es würde für Methoden verwendet, die eine veränderbare Form haben (z. B. sortund sortInPlace). Sie würden hinzufügen @warn_unused_result(mutable_variant="mutableMethodHere"), um dem Compiler davon zu erzählen.

Bei Swift 3 wird das Verhalten jedoch umgedreht. Alle Methoden warnen jetzt, dass der Rückgabewert nicht erfasst wird. Wenn Sie dem Compiler mitteilen möchten, dass die Warnung nicht erforderlich ist, fügen Sie sie @discardableResultvor der Methodendeklaration hinzu.

Wenn Sie den Rückgabewert nicht verwenden möchten, müssen Sie dies dem Compiler explizit mitteilen, indem Sie ihn einem Unterstrich zuweisen:

_ = someMethodThatReturnsSomething()

Motivation, dies zu Swift 3 hinzuzufügen:

  • Verhinderung möglicher Fehler (z. sortB. durch das Denken, dass die Sammlung geändert wird)
  • Explizite Absicht, das Ergebnis für andere Mitarbeiter nicht zu erfassen oder erfassen zu müssen

Die UIKit-API scheint dahinter zu stehen und fügt nicht @discardableResultfür die völlig normale (wenn nicht häufigere) Verwendung hinzu, popViewController(animated:)ohne den Rückgabewert zu erfassen.

Weiterlesen

tktsubota
quelle
15
Dies ist (meiner Meinung nach ) auf jeden Fall ein Schritt zurück von Swift 2, vor allem , wenn es Methoden wie diese , die, obwohl sie tun einen Wert zurückgeben, gibt es absolut gültige Anwendungsfälle , wo man es nicht nur verwenden.
Nicolas Miari
15
1. Sie brauchen das nicht let: Sie können einfach _ zuweisen, ohne es mit letoder vorangestellt zu haben var.
Rickster
1
@rickster Wusste nicht, dass die Antwort hinzufügen wird.
tktsubota
5
2. @NicolasMiari Fehler melden . Es gibt eine Annotation ( @discardableResult) für Funktionen, die einen Wert zurückgeben, bei denen jedoch erwartet wird, dass der Rückgabewert ignoriert wird. UIKit hat diese Anmerkung einfach nicht auf ihre API angewendet.
Rickster
37
Das ist eine schreckliche Syntax. Warum sollten sie das tun? Yuck.
David S.
38

Wenn das Leben Ihnen Zitronen gibt, machen Sie eine Erweiterung:

import UIKit

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

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

Beachten Sie, dass das Hinzufügen von so etwas zu @discardableResult func pop(animated: Bool) -> UIViewController?derselben Warnung führt, die Sie vermeiden möchten.

Mit der Erweiterung können Sie jetzt schreiben:

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

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

Bearbeiten: PopToRoot wurde ebenfalls hinzugefügt.

CodeReaper
quelle
Dies sollte die akzeptierte Lösung sein, da dies die sauberste Lösung für das ist, was in einem Xcode-Update sicher behoben werden kann.
Philip Broadway
24

In Swift 3 führt das Ignorieren des Rückgabewerts einer Funktion mit einem deklarierten Rückgabewert zu einer Warnung.

Eine Möglichkeit, dies zu deaktivieren, besteht darin, die Funktion mit dem @discardableResultAttribut zu markieren . Da Sie keine Kontrolle über diese Funktion haben, funktioniert dies nicht.

Die andere Methode, um die Warnung zu entfernen, besteht darin, den Wert zuzuweisen _. Dies teilt dem Compiler mit, dass Sie wissen, dass die Methode einen Wert zurückgibt, diesen jedoch nicht im Speicher behalten möchten.

let _ = navigationController?.popViewController(animated: true)
Matthew Seaman
quelle
2
Ich denke, wir müssen uns an das Hässliche halten, _bis Apple UIKit mit diesem neuen Attribut aktualisiert.
Nicolas Miari
2
Funktioniert leider @discardableResultnicht (zumindest krächzt es noch mit 8b4). Friedrich Schiller liebte faule Äpfel. Wahrscheinlich Geschmackssache :-(
qwerty_so
5

Screenshot 1

Obwohl es work correctly if kept as it isdoch dienumber of warning increases.

Die Lösung ist einfach, replace it with underscore ( _ )obwohl es hässlich zu sein scheint.

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

Screenshot 2

Jayprakash Dubey
quelle
2

Verwenden Sie in diesem Zustand discardableResult .

Gemäß <Swift Programming Language>, Kapitel Sprachreferenz - Attribute.

discardableResult

Wenden Sie dieses Attribut auf eine Funktions- oder Methodendeklaration an, um die Compilerwarnung zu unterdrücken, wenn die Funktion oder Methode, die einen Wert zurückgibt, aufgerufen wird, ohne das Ergebnis zu verwenden.

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

Es gibt auch eine Demo in <Swift Programming Language>, Kapitel Sprachhandbuch - Methoden.

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

Da es sich nicht unbedingt um einen Fehler für Code handelt, der die Methode advanced (to :) aufruft, um den Rückgabewert zu ignorieren, ist diese Funktion mit dem Attribut @discardableResult gekennzeichnet. Weitere Informationen zu diesem Attribut finden Sie unter Attribute.

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

schwarze Perle
quelle
0

Wenn Sie Erweiterungen wie die Antwort von CodeReaper verwenden möchten, sollten Sie diese verwenden @descardableResult. Dies behält alle Möglichkeiten bei, bringt aber die Warnung zum Schweigen.

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
quelle
-1

Eine andere Möglichkeit besteht darin, den self.navigationController?Wert zu entpacken und die popViewControllerFunktion aufzurufen .

    if let navigationController = navigationController {
        navigationController.popViewController(animated: true)
    }
Muazhud
quelle