Xcode 8 / Swift 3: «Выражение типа UIViewController? не используется »предупреждение

230

У меня есть следующая функция, которая скомпилирована чисто ранее, но генерирует предупреждение с Xcode 8.

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

Msgstr "Выражение типа" UIViewController? "Не используется".

Почему это говорит, и есть ли способ удалить это?

Код выполняется как ожидалось.

Gruntcakes
источник

Ответы:

498

TL; DR

popViewController(animated:)возвращает UIViewController?, и компилятор выдает это предупреждение, так как вы не фиксируете значение. Решение состоит в том, чтобы назначить это подчеркивание:

_ = navigationController?.popViewController(animated: true)

Swift 3 Change

До Swift 3 все методы по умолчанию имели «отбрасываемый результат». Никакого предупреждения не произойдет, если вы не поймете, что возвратил метод.

Чтобы сообщить компилятору, что результат должен быть получен, вы должны были добавить его @warn_unused_resultдо объявления метода. Он будет использоваться для методов, которые имеют изменяемую форму (например, sortи sortInPlace). Вы бы добавили, @warn_unused_result(mutable_variant="mutableMethodHere")чтобы сообщить об этом компилятору.

Однако в Swift 3 поведение переворачивается. Все методы теперь предупреждают, что возвращаемое значение не фиксируется. Если вы хотите сообщить компилятору, что предупреждение не нужно, вы добавляете его @discardableResultперед объявлением метода.

Если вы не хотите использовать возвращаемое значение, вы должны явно указать компилятору, присвоив его подчеркиванию:

_ = someMethodThatReturnsSomething()

Мотивация для добавления этого в Swift 3:

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

UIKit API, кажется, отстает от этого, не добавляя @discardableResultдля совершенно нормального (если не более общего) использования popViewController(animated:)без захвата возвращаемого значения.

Читать далее

tktsubota
источник
15
Это (на мой взгляд), безусловно, шаг назад по сравнению с Swift 2, особенно когда есть такие методы, которые, хотя они и возвращают значение, существуют совершенно допустимые случаи использования, когда вы просто не используете его.
Николас Миари
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 тоже.

CodeReaper
источник
Это должно быть принятым решением, так как это самое чистое исправление того, что обязательно будет исправлено в обновлении 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

Используйте discardableResult в этом состоянии.

Согласно <Swift Programming Language>, глава Справочник по языку - Атрибуты.

discardableResult

Примените этот атрибут к объявлению функции или метода, чтобы подавить предупреждение компилятора, когда функция или метод, который возвращает значение, вызывается без использования его результата.

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

Также есть демонстрация в <Swift Programming Language>, глава Language Guide - Методы.

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

Поскольку код, вызывающий метод advance (to :), не обязательно игнорирует возвращаемое значение, не обязательно является ошибкой, эта функция помечается атрибутом @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)
    }
muazhud
источник