如何在 Xcode 8.3 beta 中解决 "String interpolation produces a debug description for an optional value; did you mean to make this explicit?"?

How to solve "String interpolation produces a debug description for an optional value; did you mean to make this explicit?" in Xcode 8.3 beta?

自 beta 8.3 以来,无数警告 "String interpolation produces a debug description for an optional value; did you mean to make this explicit?" 出现在我的代码中。

例如,在以下情况弹出警告,其中 options 可能导致 nil:

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

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

编译器建议添加一个String构造函数,描述如下:

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

显然,结果很明确,但在我看来也非常繁琐。有更好的选择吗?我是否必须修复所有这些警告或更好地等待下一个测试版?

这是在 this pull request due to the fact that interpolating Optional(...) into the resultant string is often undesirable, and can be especially surprising . You can see the full discussion of this change on the mailing list here 中所做的更改。

正如 pull request discussion 中提到的(虽然不幸的是 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

在Swift5中,随着SE-0228, another option is to add a custom appendInterpolation overload for 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

虽然我个人更愿意保留参数标签。

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

默认值??对非字符串没有意义,例如 Int.
如果 Int 为 nil 那么您希望日志显示 'nil' 不是默认为另一个 Int 例如0.

一些要测试的 playground 代码:

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

更新到 Xcode 8.3 后收到很多警告消息,我想出了以下更像原始输出行为,易于添加,减少了使用 [=23 的冗长=] 在代码和输出中。

基本上,添加一个 Optional 扩展名,它提供一个描述可选内容的字符串,如果未设置,则简单地 "nil"。另外,如果optional里的东西是String,就放在引号里。

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"

感谢关注 link:

的帮助

check-if-variable-is-an-optional-and-what-type-it-wraps

See Ole Begeman's fix for this。我喜欢它。它会创建一个 ??? 运算符,然后您可以像这样使用它:

var someValue: Int? = 5
print("The value is \(someValue ??? "unknown")")
// → "The value is 5"
someValue = nil
print("The value is \(someValue ??? "unknown")")
// → "The value is unknown"

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

  1. 使用 String(describing:) 消除此警告:

    使用它会变成String(describing:<Variable>)

    例如。 : String(describing: employeeName)

  2. 提供一个default value以避免这个警告:

    使用它会变成(<Variable> ?? default value)

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

处理此问题的两种更简单的方法。

选项 1:

第一个是 "force-unwrapping" 你想要的值 return 使用 bang (!)

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

输出:

5

选项 2:

另一种可能是更好的方法 - 是 "safely-unwrap" 你想要的值 return编辑。

var someValue: Int? = 5

if let newValue = someValue {
    print(newValue)
}

输出:

5

建议选择选项 2。

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

Swift 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>|⭕️

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

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