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?

SwiftSwift3OptionalString Interpolation

Swift Problem Overview


Since beta 8.3, zillions warnings "String interpolation produces a debug description for an optional value; did you mean to make this explicit?" appeared in my code.

For example, the warning popped in the following situation up, where options could lead to nil:

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

As previously designed, it was ok for me (and the compiler) the optionals to be interpolated as 'nil'. But compiler changed its mind.

What the compiler suggests is to add a String constructor with description as follows:

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

Obviously, the results is explicit but also very very cumbersome in my opinion. Is there a better option? Do I have to fix all those warning or better wait for the next beta?

Screenshot for description

Swift Solutions


Solution 1 - Swift

This is a change that was made in this pull request due to the fact that interpolating Optional(...) into the resultant string is often undesirable, and can be especially surprising in cases with implicitly unwrapped optionals. You can see the full discussion of this change on the mailing list here.

As mentioned in the pull request discussion (although unfortunately not by Xcode) – one slightly nicer way to silence the warning than the use of String(describing:) is to add a cast to the optional type of whatever you're interpolating, so for example:

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

Which can also be generalised to 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

In Swift 5, with the new string interpolation system introduced by 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

And, if desired, you could even remove the argument label to disable the warning entirely within a module (or within a particular file if you mark it as 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

Though personally I would prefer to keep the argument label.

Solution 2 - Swift

Two easier ways of dealing with this issue.

Option 1:

The first would be by "force-unwrapping" the value you would like to return using a bang (!)

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

Output:

5

Option 2:

The other way, which could be the better way - is to "safely-unwrap" the value you want returned.

var someValue: Int? = 5

if let newValue = someValue {
    print(newValue)
}

Output:

5

Would recommend to go with option 2.

Tip: Avoid force unwrapping (!) where possible as we are not sure if we will always have the value to be unwrapped.

Solution 3 - Swift

seems using String(describing:optional) is simplest.

default value ?? makes no sense for non-Strings e.g Int.
If Int is nil then you want the log to show 'nil' not default to another Int e.g. 0.

Some playground code to test:

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

Output

optionalString: nil
optionalInt: nil

Solution 4 - Swift

After updating to Xcode 8.3 and getting a lot of warning messages, I came up with the following that is more like the original output behavior, easy to add in, reduces the verboseness of using "String(describing:)" both in code and output.

Basically, add an Optional extension that gives a String describing the thing in the optional, or simply "nil" if not set. In addition, if the thing in the optional is a String, put it in quotes.

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

And usage in a playground:

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"

Thanks for help from following link:

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

Solution 5 - Swift

See Ole Begeman's fix for this. I love it. It creates a ??? operator which you can then use like 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"

Solution 6 - Swift

Double click on the yellow triangle displayed on line containing this warning. This will show FixIt with two solutions.

Screenshot added

  1. Use String(describing:) to silence this warning :

    Using this it will become String(describing:<Variable>)

    Eg. : String(describing: employeeName)

  2. Provide a default value to avoid this warning :

    Using this it will become (<Variable> ?? default value)

    Eg.: employeeName ?? “Anonymous” as! String

Solution 7 - Swift

Swift 5

My solution is making an extension which unwrap Optional object to Any.

When you log the object or print it out, you can see the actual object or <nil>⭕️ (combination from text and visual character). It's useful to look at, especially in the console log.

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

Solution 8 - Swift

Create an interpolation method that accepts an optional generic Type with an unnamed parameter. All your annoying warnings will magically disappear.

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSt&#233;phane de LucaView Question on Stackoverflow
Solution 1 - SwiftHamishView Answer on Stackoverflow
Solution 2 - SwiftMo IisaView Answer on Stackoverflow
Solution 3 - Swiftbrian.clearView Answer on Stackoverflow
Solution 4 - SwiftanorskdevView Answer on Stackoverflow
Solution 5 - Swiftdar512View Answer on Stackoverflow
Solution 6 - SwiftJayprakash DubeyView Answer on Stackoverflow
Solution 7 - Swiftnahung89View Answer on Stackoverflow
Solution 8 - SwiftScottyBladesView Answer on Stackoverflow