如何解决“字符串插值为可选值生成调试描述;你是说要明确吗?” 在Xcode 8.3 beta中?


87

从beta 8.3开始,成千上万的警告“字符串插值会为可选值生成调试说明;您是要明确显示此值?” 出现在我的代码中。

例如,在以下情况下会弹出警告,其中选项可能会导致无效:

let msg = "*** Error \(options["taskDescription"]): cannot load \(sUrl) \(error)"

按照之前的设计,对于我(和编译器)来说,可以将可选值插值为“ nil”是可以的。但是编译器改变了主意。

编译器建议的是添加一个具有以下描述的String构造函数:

let msg = "*** Error \(String(describing: options["taskDescription"])): cannot load \(sUrl) \(error)"

显然,结果在我看来是明确的,但也非常麻烦。有更好的选择吗?我是否必须解决所有这些警告,或者更好地等待下一个Beta?

截图说明


26
真是个令人讨厌的警告……
乔尼

Swift 3打破了我自己log的想法,而我只是通过print改用而犯了一个错误。应该始终创建自己的包装器,否则您会被这种“新功能”所困扰。
superarts.org

Answers:


105

这是在此拉取请求中进行的更改,原因是这样的事实,即插值Optional(...)到结果字符串中通常是不希望的,在具有隐式展开的optionals的情况下,这尤其令人惊讶。您可以在此处的邮件列表中看到有关此更改的完整讨论。

正如拉取请求讨论中提到的(尽管不幸的是,不是Xcode提出的)–使警告静音的一种比使用更好的方法String(describing:)是将强制类型转换添加到要插值的可选类型中,例如:

var i: Int? = 5
var d: Double? = nil

print("description of i: \(i as Int?)")    // description of i: Optional(5)
print("description of d: \(d as Double?)") // description of d: nil

也可以概括为as Optional

print("description of i: \(i as Optional)") // description of i: Optional(5)
print("description of d: \(d as Optional)") // description of d: nil

在Swift 5中,SE-0228引入了新的字符串插值系统,另一个选择是为以下项添加自定义appendInterpolation重载DefaultStringInterpolation

extension DefaultStringInterpolation {
  mutating func appendInterpolation<T>(optional: T?) {
    appendInterpolation(String(describing: optional))
  }
}

var i: Int? = 5
var d: Double? = nil

print("description of i: \(optional: i)") // description of i: Optional(5)
print("description of d: \(optional: d)") // description of d: nil

而且,如果需要,您甚至可以删除参数标签以完全在模块内(或在标记为的情况下在特定文件内)禁用警告fileprivate

extension DefaultStringInterpolation {
  mutating func appendInterpolation<T>(_ optional: T?) {
    appendInterpolation(String(describing: optional))
  }
}

var i: Int? = 5
var d: Double? = nil

print("description of i: \(i)") // description of i: Optional(5)
print("description of d: \(d)") // description of d: nil

虽然我个人更希望保留论点标签。


从提案中,尚不清楚这种变化是否将是永久的?你怎么看?@Hamish
Stéphanede Luca)

@StéphanedeLuca在邮件列表中,关于其他解决方案的讨论很多,例如允许?? "nil"静默警告,这似乎很受欢迎,因此可能会在不久的将来出现在另一个提案中。我确实同意这种解决方法不是理想的选择-就我个人而言,我认为期望Optional(...)将其内插到字符串中以提供强大的可选功能是很明显的-只有IUO确实需要此警告IMO。但是Swift一直在发展,所以这一切都可能在以后改变。但是现在,这就是我们所拥有的。
Hamish

我还偶然发现了一个有点“相关”的问题,是否可以在这里不拆箱stackoverflow.com/questions/42543512 / ...如果您可以看一下?@Hamish
Stéphanede Luca)

...在任何情况下,此代码都是疯狂的:guard result == nil else { print("result was \(result as Optional)") return }
loretoparisi

1
@loretoparisi为什么不使用if let?即if let result = result { print("result was \(result)"); return }。并非所有的早期归还都需要警卫来完成。
Hamish

29

解决此问题的两种简单方法。

选项1:

第一种是通过“强制展开” 您想使用爆炸(!)返回的值

var someValue: Int? = 5
print(someValue!)

输出:

5

选项2:

另一种方法(可能是更好的方法)是“安全地解包”您要返回的值。

var someValue: Int? = 5

if let newValue = someValue {
    print(newValue)
}

输出:

5

建议选择选项2。

提示:尽可能避免强行解包(!),因为我们不确定是否总是需要解包的值。


1
我是新手,但我喜欢选项2在打印前验证包装,并且您始终可以选择在展开包装时打印其他东西
AbuTaareq

16

似乎使用String(describing:optional)是最简单的。

默认值 ??对于非字符串,例如Int,没有任何意义。
如果Int为nil,那么您希望日志显示“ nil”不是默认的另一个Int,例如0。

一些游乐场代码来测试:

var optionalString : String? = nil
var optionalInt : Int? = nil

var description_ = ""
description_ = description_ + "optionalString: \(String(describing: optionalString))\r"
description_ = description_ + "   optionalInt: \(String(describing: optionalInt))\r"

print(description_)

输出量

optionalString: nil
optionalInt: nil

13

更新到Xcode 8.3并收到许多警告消息后,我想到了以下内容,它更像是原始输出行为,易于添加,减少了在代码和输出中同时使用“ String(describing :)”的冗长性。

基本上,添加一个Optional扩展,该扩展提供一个String来描述可选内容中的内容,如果未设置,则简单地为“ nil”。另外,如果可选中的东西是字符串,则将其用引号引起来。

extension Optional {
    var orNil : String {
        if self == nil {
            return "nil"
        }
        if "\(Wrapped.self)" == "String" {
            return "\"\(self!)\""
        }
        return "\(self!)"
    }
}

以及在操场上的用法:

var s : String?
var i : Int?
var d : Double?

var mixed = "s = \(s.orNil)    i = \(i.orNil)   d = \(d.orNil)" // "s = nil    i = nil   d = nil"

d = 3
i = 5
s = ""
mixed = "s = \(s.orNil)    i = \(i.orNil)   d = \(d.orNil)" // "s = ""    i = 5   d = 3.0"

s = "Test"
d = nil
mixed = "s = \(s.orNil)    i = \(i.orNil)   d = \(d.orNil)" // "s = "Test"    i = 5   d = nil"

感谢您通过以下链接获得帮助:

检查变量是否是可选的,包装什么类型


此解决方案不适用于可选链。喜欢a?.b?.c.orNil
Vincent Sit


8

双击包含此警告的行上显示的黄色三角形。这将显示具有两种解决方案的FixIt

屏幕截图已添加

  1. 使用 String(describing:)沉默这样的警告:

    使用它,它将成为 String(describing:<Variable>)

    例如。:String(describing: employeeName)

  2. 提供一个 default value来避免此警告:

    使用它,它将成为 (<Variable> ?? default value)

    例如。: employeeName ?? “Anonymous” as! String


1
是的,我也会去参加Nil-Coalescing运营商:developer.apple.com/library/content/documentation/Swift/…–
kevinius

1
好答案!如果您要提供其他字符串值,则零促销可与此一起很好地工作
Lance Samaria

1

迅捷5

我的解决方案是使对象成为extension哪个Optional对象Any

登录或打印对象时,您可以看到实际的object<nil>⭕️(文本和视觉字符的组合)。查看它很有用,尤其是在控制台日志中。

extension Optional {
    var logable: Any {
        switch self {
        case .none:
            return "<nil>|⭕️"
        case let .some(value):
            return value
        }
    }
}

// sample
var x: Int?
print("Logging optional without warning: \(x.logable)")
// → Logging optional without warning: <nil>|⭕️

0

创建一个插值方法,该方法接受带有未命名参数的可选通用类型。您所有烦人的警告都会神奇地消失。

extension DefaultStringInterpolation {
  mutating func appendInterpolation<T>(_ optional: T?) {
    appendInterpolation(String(describing: optional))
  }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.