来自字符串插值的警告

Warnings from String interpolation

我遇到了自己无法解决的问题。我尝试过上网,但没有成功。

我对 Swift 和编码还是很陌生,现在正在按照帮助我创建应用程序的指南进行操作。

不幸的是,据我所知,该应用程序是为 Swift 3 编写的,由于我使用的是 Swift 4.

,因此给我带来了一些问题

我必须要给出此警告的行:

String interpolation produces a debug description for an optional value; did you mean to make this explicit?

Use 'String(describing:)' to silence this warning Fix

Provide a default value to avoid this warning Fix

但是,当我单击 Xcode 的解决方案之一时,我遇到了另一个问题。

如果我使用第一个修复程序,应用程序崩溃并且我收到以下消息:

Thread 1: Fatal error: Unexpected Segue Identifier;

如果我使用第二个修复程序,我必须指定一个默认值。而且我不知道这应该是什么。

整段代码如下。 这是导致问题的以 guard let selectedMealCell 开头的行和 default: 之后的最后一行。

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    super.prepare(for: segue, sender: sender)
    
    switch(segue.identifier ?? "") {
    case "AddItem":
        os_log("Adding a new meal.", log: OSLog.default, type: .debug)

    case "ShowDetail":
        guard let mealDetailViewController = segue.destination as? MealViewController else {
            fatalError("Unexpected destination: \(segue.destination)")
        }
        
        guard let selectedMealCell = sender as? MealTableViewCell else {
            fatalError("Unexpected sender: \(sender)")
        }
        
        guard let indexPath = tableView.indexPath(for: selectedMealCell) else {
            fatalError("The selected cell is not being displayed by the table")
        }
        
        let selectedMeal = meals[indexPath.row]
        mealDetailViewController.meal = selectedMeal
        
    default:
        fatalError("Unexpected Segue Identifier; \(segue.identifier)")
    }
}

因此,第一个建议的修复对您有用。它消除了编译时警告,尽管不可否认 String(describing:) 是一个薄弱的解决方案。

在这两种情况下,您都需要解包可选值。对于第一种情况,您应该使用:

guard let selectedMealCell = sender as? MealTableViewCell else {
    if let sender = sender {
        fatalError("Unexpected sender: \(sender))")
    } else {
        fatalError("sender is nil")
    }
}

在第二种情况下:

fatalError("Unexpected Segue Identifier; \(segue.identifier ?? "")")

然后你得到一个运行时错误:

"Unexpected Segue Identifier;"

这表明您的 switch 与前 2 个案例不匹配,运行 与 default 案例不匹配。崩溃是因为您的代码显式调用了 fatalError。您的 segue.identifier 显然是一个空字符串。

所以你的问题实际上是在你的情节提要中。您需要为您的 segues 分配标识符。单击视图控制器之间的转场箭头,并将标识符 "AddItem""ShowDetail" 分配给正确的转场。 segue identifier在Xcode.

右侧的Attributes Inspector中赋值

如果您准备为 Optional 编写一个小扩展,它可以使插入可选变量值的业务变得不那么痛苦,并且避免必须重复编写 optionalVar ?? ""

鉴于:

extension Optional: CustomStringConvertible {

    public var description: String {
        switch self {
        case .some(let wrappedValue):
            return "\(wrappedValue)"
        default:
            return "<nil>"
        }
    }
}

那你可以这样写:

var optionalWithValue: String? = "Maybe"
var optionalWithoutValue: String?

print("optionalWithValue is \(optionalWithValue.description)")
print("optionalWithoutValue is \(optionalWithoutValue.description)")

给出:

optionalWithValue is Maybe
optionalWithoutValue is <nil>

你也可以写 print("value is \(anOptionalVariable)")——.description 是多余的,因为 print() 无论如何都使用 CustomStringConvertible.description——但尽管它有效,你仍然会收到烦人的编译器警告。

您可以使用以下内容为 nil 值自动生成“nil”(或任何其他字符串),对于 non-nil 值使用 CustomStringConvertible[=16 提供的 description =]

extension String.StringInterpolation {
    mutating func appendInterpolation<T: CustomStringConvertible>(_ value: T?) {
        appendInterpolation(value ?? "nil" as CustomStringConvertible)
    }
}

对于您自己的类型,您必须符合 CustomStringConvertible 才能工作:

class MyClass: CustomStringConvertible {
    var description: String {
        return "Whatever you want to print when you use MyClass in a string"
    }
}

通过此设置,您可以像使用任何其他类型一样简单地使用可选类型,而不会出现任何编译器警告。

var myClass: MyClass?
myClass = MyClass()
print("myClass is \(myClass)")