Как решить «Интерполяция строк дает описание отладки для необязательного значения; вы хотели сделать это явным? " в бета-версии Xcode 8.3?

87

Начиная с бета-версии 8.3, огромное количество предупреждений: «Строковая интерполяция дает описание отладки для необязательного значения; вы хотели сделать это явным?» появился в моем коде.

Например, предупреждение появляется в следующей ситуации, когда параметры могут привести к нулю:

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

Как было разработано ранее, для меня (и для компилятора) было нормально, что дополнительные параметры должны быть интерполированы как 'nil'. Но компилятор передумал.

Компилятор предлагает добавить конструктор String со следующим описанием:

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

Очевидно, что результаты явные, но, на мой взгляд, очень громоздкие. Есть ли лучший вариант? Мне нужно исправить все эти предупреждения или лучше дождаться следующей бета-версии?

Снимок экрана для описания

Стефан де Лука
источник
26
Какое действительно досадное предупреждение ...
Джонни
Swift 3сломал свой собственный, logи я сделал ошибку, просто используя printвместо этого. Всегда нужно создавать свою собственную оболочку, иначе вы будете втянуты в эту «новую функцию».
superarts.org 03

Ответы:

105

Это изменение было внесено в этот пул-реквест из-за того, что интерполяция Optional(...)в результирующую строку часто нежелательна и может быть особенно неожиданной в случаях с неявно развернутыми опциями . Вы можете увидеть полное обсуждение этого изменения в списке рассылки здесь .

Как упоминалось в обсуждении запроса на вытягивание (хотя, к сожалению, не в 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éphanedeLuca В списке рассылки было довольно много дискуссий о других решениях, таких как разрешение на ?? "nil"отключение предупреждения, которое, казалось, было умеренно популярным, поэтому может появиться в другом предложении в ближайшем будущем. Я согласен с тем, что этот обходной путь далеко не идеален - лично я считаю довольно очевидным ожидать, Optional(...)что он будет вставлен в строку для сильного необязательного параметра - это действительно был только случай IUO, который нуждался в этом предупреждении IMO. Но Swift постоянно развивается, так что все это может измениться позже. Но пока это то, что у нас есть.
Хэмиш
Я также наткнулся на несколько «связанную» проблему в том, что если вы позволите больше не распаковывать здесь stackoverflow.com/questions/42543512/… если вы можете взглянуть? @Hamish
Стефан де Лука
... в любом случае этот код - безумие: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 (описание: необязательно) является самым простым.

значение по умолчанию ?? не имеет смысла для не-строк, например Int.
Если Int равен нулю, тогда вы хотите, чтобы журнал показывал «ноль», а не по умолчанию для другого 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
brian.clear
источник
13

После обновления до Xcode 8.3 и получения большого количества предупреждающих сообщений я придумал следующее, которое больше похоже на исходное поведение вывода, легко добавляется, уменьшает многословность использования «Строка (описание :)» как в коде, так и в выводе. .

По сути, добавьте необязательное расширение, которое дает строку, описывающую предмет в необязательном, или просто "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"

Спасибо за помощь по следующей ссылке:

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

Anorskdev
источник
Это решение не работает в дополнительной цепочке. Нравится a?.b?.c.orNil.
Винсент Сид
11

См. Исправление Оле Бегемана . Я люблю это. Он создает ???оператор, который затем можно использовать следующим образом:

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"
dar512
источник
5
Ссылка на его сообщение в блоге, описывающее это, было бы полезно, я думаю: oleb.net/blog/2016/12/optionals-string-interpolation
Николай Хенриксен
8

Дважды щелкните желтый треугольник, отображаемый в строке, содержащей это предупреждение. Это покажет FixIt с двумя решениями.

Скриншот добавлен

  1. Используйте, String(describing:)чтобы отключить это предупреждение:

    Используя это, он станет String(describing:<Variable>)

    Например. :String(describing: employeeName)

  2. Обеспечить , default valueчтобы избежать этого предупреждения:

    Используя это, он станет (<Variable> ?? default value)

    Например.: employeeName ?? “Anonymous” as! String

Джайпракаш Дубей
источник
1
Да, я бы также
выбрал
1
Отличный ответ! Нулевое объединение хорошо работает с этим, если у вас есть альтернативное строковое значение, которое нужно предоставить
Лэнс Самария
1

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>|⭕️
nahung89
источник
0

Создайте метод интерполяции, который принимает необязательный универсальный тип с безымянным параметром. Все ваши надоедливые предупреждения волшебным образом исчезнут.

extension DefaultStringInterpolation {
  mutating func appendInterpolation<T>(_ optional: T?) {
    appendInterpolation(String(describing: optional))
  }
}
СкоттиБлейдс
источник