Xcode 8 / Swift 3:「Expression of type UIViewController? is unused」警告

236

我有以下函数,之前编译时一切正常,但在Xcode 8中会生成警告。

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

“Expression of type "UIViewController?" is unused”。

为什么会出现这种提示,是否有方法可以去除它?

代码的执行符合预期。

7个回答

505

简述

popViewController(animated:) 方法返回 UIViewController? 类型,编译器因为你没有捕获该值而发出警告。解决方法是将其赋值给下划线:

```swift _ = navigationController?.popViewController(animated: true) ```
_ = navigationController?.popViewController(animated: true)

Swift 3变更

在Swift 3之前,默认情况下所有方法都有一个“可丢弃的结果”。当您没有捕获方法返回值时,不会发出任何警告。

为了告诉编译器结果应该被捕获,您必须在方法声明之前添加@warn_unused_result。它将用于具有可变形式的方法(例如sortsortInPlace)。您可以添加@warn_unused_result(mutable_variant="mutableMethodHere")来告诉编译器这一点。

然而,在Swift 3中,行为被颠倒了。现在所有方法都会警告返回值未被捕获。如果想要告诉编译器不需要警告,请在方法声明之前添加 @discardableResult

如果您不想使用返回值,您必须显式地通过将其赋值给下划线来告诉编译器:

_ = someMethodThatReturnsSomething()

添加此功能到Swift 3的动机:

  • 防止可能出现的错误(例如,使用sort时认为它修改了集合)
  • 明确表示不捕获或不需要捕获结果以供其他协作者使用

看起来UIKit API落后于此,没有为popViewController(animated:)正常(如果不是更常见的话)的用途添加@discardableResult以避免捕获返回值。

阅读更多


15
在我看来,这绝对是相对于Swift 2的倒退,特别是当有像这样的方法,即使它们确实会返回一个值,但有完全合理的用例你并不需要使用它。 - Nicolas Miari
16
你不需要使用 let,你可以直接给 _ 赋值,无需在之前加上 letvar - rickster
1
@rickster 不知道会加入回答。 - tktsubota
5
请到 bugreport.apple.com 提交一个错误报告。有一个名为 @discardableResult 的注释是用于标识那些虽然返回值但是可以忽略其返回值的函数。但是,UIKit尚未将该注释应用于其API中。 - rickster
37
这个语法太糟糕了,他们为什么要这样做?呸。 - David S.
显示剩余9条评论

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更新中得到修复。 - xivusr

24
在Swift 3中,忽略具有声明返回值的函数的返回值将导致警告。 另一种避免这种情况的方法是使用@discardableResult属性标记该函数。由于您无法控制此函数,因此该方法不适用。 另一种消除警告的方法是将其赋值给_。这告诉编译器您知道该方法返回一个值,但您不希望将其保留在内存中。
let _ = navigationController?.popViewController(animated: true)

2
我猜我们只能继续使用丑陋的“_”,直到苹果更新UIKit以支持这个新属性。 - Nicolas Miari
2
不幸的是,@discardableResult 不起作用(至少在 8b4 中仍然会出错)。弗里德里希·席勒喜欢烂苹果。可能只是个人口味问题 :-( - qwerty_so

5

屏幕截图1

虽然如果保持原样,它可以正常工作,但是警告的数量会增加。

解决方案是简单地用下划线(_)替换它,尽管看起来有点丑陋。

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

Screenshot 2


3
在这种情况下,请使用discardableResult
根据<Swift编程语言>,第35章 - 属性

discardableResult

将此属性应用于函数或方法声明,以抑制编译器警告,当调用返回值的函数或方法时,如果不使用其结果,则会出现警告。

还有一个演示在<Swift编程语言>,第15章 - 方法
@discardableResult
mutating func advance(to level: Int) -> Bool {
    ...
    return true
}

由于调用advance(to:)方法的代码忽略返回值并不一定是错误,因此该函数标有@discardableResult属性。有关此属性的更多信息,请参见Attributes。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接