Xcode 8 / Swift 3: «Вираз типу UIViewController? не використовується "попередження


230

У мене є така функція, яка складена раніше чисто, але генерує попередження з Xcode 8.

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

"Вираз типу" UIViewController? "Не використовується".

Чому це говорять і чи є спосіб її видалити?

Код виконується як очікувалося.

Відповіді:


498

TL; DR

popViewController(animated:)повертається UIViewController?, і компілятор видає це попередження, оскільки ви не захоплюєте значення. Рішення полягає в призначенні його підкреслення:

_ = navigationController?.popViewController(animated: true)

Швидкий 3 Зміна

До Swift 3 всі методи мали за замовчуванням "результат, який можна зняти". Ніякого попередження не буде, якщо ви не захопили те, що повернув метод.

Для того, щоб сказати компілятору, що результат повинен бути зафіксований, вам довелося додати його @warn_unused_resultперед оголошенням методу. Він буде використовуватися для методів, що мають форму, що змінюється (наприклад, sortта sortInPlace). Ви додали @warn_unused_result(mutable_variant="mutableMethodHere")б сказати компілятору цього.

Однак із Swift 3 поведінка перевернута. Усі методи тепер попереджають, що повернене значення не захоплюється. Якщо ви хочете сказати компілятору, що попередження не потрібне, ви додасте @discardableResultперед декларацією методу.

Якщо ви не хочете використовувати значення, що повертається, вам слід чітко сказати компілятору, призначивши його підкресленням:

_ = someMethodThatReturnsSomething()

Мотивація додати це до Swift 3:

  • Попередження можливих помилок (наприклад, за допомогою sortмислення, це модифікує колекцію)
  • Явний намір не фіксувати або потребувати фіксації результату для інших співробітників

API UIKit, як видається, відстає від цього, не додаючи @discardableResultдля цілком нормального (якщо не більш звичайного) використання popViewController(animated:)без фіксації повернутого значення.

Детальніше


15
Це, на мій погляд, безумовно, крок назад від Swift 2, особливо коли існують такі методи, що, хоча вони і повертають значення, є цілком коректні випадки використання, коли ви просто не використовуєте це.
Nicolas Miari

15
1. Вам не потрібно let: ви можете просто призначити _, не передуючи цьому з letабо var.
рикстер

1
@rickster Не знав, що додасть відповідь.
tktsubota

5
2. @NicolasMiari Подайте помилку . Існує примітка ( @discardableResult) для функцій, які повертають значення, але там, де очікується, що можна ігнорувати повернене значення. UIKit просто не застосував цю примітку до свого API.
рикстер

37
Це жахливий синтаксис. Навіщо їм це робити? Гидота.
Девід С.

38

Коли життя дає вам лимони, зробіть продовження:

import UIKit

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

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

Зауважте, що додавання чогось подібного @discardableResult func pop(animated: Bool) -> UIViewController?призведе до того ж попередження, яке ви намагаєтеся уникати.

З розширенням тепер ви можете писати:

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

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

Редагувати: Додано також popToRoot.


Це має бути прийнятим рішенням, оскільки це найчистіше виправлення того, що обов'язково має бути зафіксовано в оновленнях Xcode.
Філіп Бродвей

24

У Swift 3 ігнорування повернутого значення функції, яка має оголошене значення повернення, призводить до попередження.

Один із способів відмовитися від цього - позначити функцію @discardableResultатрибутом. Оскільки ви не маєте контролю над цією функцією, це не працюватиме.

Інший спосіб позбутися попередження - присвоїти значення _. Це повідомляє компілятору, що ви знаєте, що метод повертає значення, але ви не хочете зберігати його в пам'яті.

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

2
Я думаю, нам доведеться дотримуватися негарного, _поки Apple не оновить UIKit цим новим атрибутом.
Ніколас Міарі

2
На жаль, @discardableResultце не працює (принаймні, він все ще крутить з 8b4). Фрідріх Шиллер любив гнилі яблука. Мабуть, справа смаку :-(
qwerty_so

5

Знімок екрана 1

Хоча це, work correctly if kept as it isалеnumber of warning increases.

Рішення полягає в тому, щоб просто, replace it with underscore ( _ )хоча це здається некрасивим.

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

Знімок екрана 2


2

Використовуйте disardableResult в цьому стані.

Відповідно до <Швидкої мови програмування>, довідник мови - Атрибути.

disardableResult

Застосуйте цей атрибут до декларації функції або методу, щоб придушити попередження компілятора, коли функція або метод, який повертає значення, викликаються без використання його результату.

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

Демонстраційна версія також міститься у розділі <Швидка мова програмування>, розділ Посібник з мов - Методи.

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

Оскільки це не обов'язково помилка коду, який викликає метод заздалегідь (до :), щоб ігнорувати значення повернення, ця функція позначена атрибутом @discardableResult. Для отримання додаткової інформації про цей атрибут див. Атрибути.

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


0

Якщо ви хочете пройти шлях розширень, як відповідь CodeReaper, вам слід скористатися @descardableResult. Це зберігає всі можливості, але замовчує попередження.

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

Ще один спосіб - ви можете розкрутити self.navigationController?значення та викликати popViewControllerфункцію.

    if let navigationController = navigationController {
        navigationController.popViewController(animated: true)
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.