iosswiftoption-typeforced-unwrapping

Left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used


I have a the following code which i am trying to use to initialize a variable and perform some operation on it.

let formattedPointsValue: String?
self.formattedPointsValue = model.pointUnitsEarned.stringValueWithWhiteSpaceThousandSeperator()+" "+"model.name".localized(in: .name) ?? .none

However i am getting the warning

Left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used.

When i remove the ?? .none my projects runs fine without a problem however when i run my unit tests i get an error

fatal error: unexpectedly found nil while unwrapping an Optional value

The only way i found to solve this is to use this code.

if let unformattedValue = model.pointUnitsEarned {
    self.formattedPointsValue = unformattedValue.stringValueWithWhiteSpaceThousandSeperator()+" "+"model.name".localized(in: .name)
} else {
    self.formattedPointsValue = nil
}

I would like to understand why something like this works:

let legend: String?
self.legend = model.pointsCategory ?? .none

but this fails:

let formattedPointsValue: String?
self.formattedPointsValue = model.pointUnitsEarned.stringValueWithWhiteSpaceThousandSeperator()+" "+"model.name".localized(in: .name) ?? .none

Solution

  • I think you are a little confused with the ?? operator.

    You thought this works because legend is optional, didn't you?

    let legend: String?
    self.legend = model.pointsCategory ?? .none
    

    That is not the reason! The actual reason why the above works is because model.pointsCategory is optional. It has nothing to do with what's on the left hand side of the =. It's all about the operand on the left of ??. So the above says something like this:

    set self.legend to model.pointsCategory if model.pointsCategory is not nil. If it is nil, set self.legend to .none.

    In this case:

    self.formattedPointsValue = model.pointUnitsEarned.stringValueWithWhiteSpaceThousandSeperator()+
        " "+"model.name".localized(in: .name) ?? .none
    

    Since "model.name".localized(in: .name) is not an optional, it does not compile. I suspect that what you intended to do here might be this:

    if self.formattedPointsValue == nil {
        self.formattedPointsValue = .none
    } else {
       self.formattedPointsValue = model.pointUnitsEarned.stringValueWithWhiteSpaceThousandSeperator()+
            " "+"model.name".localized(in: .name)
    }