Cách giải quyết “Nội suy chuỗi tạo ra mô tả gỡ lỗi cho một giá trị tùy chọn; bạn có ý định làm cho điều này rõ ràng? " trong Xcode 8.3 beta?


87

Kể từ phiên bản beta 8.3, cảnh báo zillions "Nội suy chuỗi tạo ra mô tả gỡ lỗi cho một giá trị tùy chọn; ý của bạn là làm rõ ràng điều này?" xuất hiện trong mã của tôi.

Ví dụ: cảnh báo xuất hiện trong tình huống sau, nơi các tùy chọn có thể dẫn đến con số không:

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

Như đã thiết kế trước đó, đối với tôi (và trình biên dịch), các tùy chọn được nội suy là 'nil' là ổn. Nhưng trình biên dịch đã thay đổi ý định.

Những gì trình biên dịch đề xuất là thêm một phương thức khởi tạo chuỗi với mô tả như sau:

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

Rõ ràng, kết quả là rõ ràng nhưng cũng rất phức tạp theo quan điểm của tôi. Có lựa chọn nào tốt hơn không? Tôi có phải khắc phục tất cả những cảnh báo đó hay tốt hơn là đợi bản beta tiếp theo?

Ảnh chụp màn hình để mô tả


26
Thật là một cảnh báo thực sự gây phiền nhiễu ...
Jonny

Swift 3đã phá vỡ của riêng tôi logvà tôi đã mắc lỗi bằng cách sử dụng printthay thế. Nên luôn tạo trình bao bọc của riêng bạn, nếu không bạn sẽ bị loại "tính năng mới" này làm rối tung.
superarts.org

Câu trả lời:


105

Đây là một thay đổi đã được thực hiện trong yêu cầu kéo này do thực tế là nội suy Optional(...)vào chuỗi kết quả thường không được mong muốn và có thể đặc biệt đáng ngạc nhiên trong các trường hợp có các tùy chọn không được bao bọc hoàn toàn . Bạn có thể xem toàn bộ cuộc thảo luận về sự thay đổi này trong danh sách gửi thư tại đây .

Như đã đề cập trong cuộc thảo luận về pull request (mặc dù rất tiếc không phải bởi Xcode) - một cách tốt hơn một chút để tắt tiếng cảnh báo so với việc sử dụng String(describing:)là thêm một cast vào loại tùy chọn của bất cứ thứ gì bạn đang nội suy, ví dụ:

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

Điều này cũng có thể được khái quát thành 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

Trong Swift 5, với hệ thống nội suy chuỗi mới được SE-0228 giới thiệu , một tùy chọn khác là thêm appendInterpolationquá tải tùy chỉnh cho 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

Và, nếu muốn, bạn thậm chí có thể xóa nhãn đối số để vô hiệu hóa hoàn toàn cảnh báo trong một mô-đun (hoặc trong một tệp cụ thể nếu bạn đánh dấu nó là 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

Mặc dù cá nhân tôi muốn giữ nhãn đối số.


Từ đề xuất, không rõ liệu sự thay đổi này có lâu dài hay không? Bạn nghĩ sao? @Hamish
Stéphane de Luca

@ StéphanedeLuca Đã có khá nhiều thảo luận trong danh sách gửi thư về các giải pháp khác như cho phép tắt tiếng ?? "nil"cảnh báo, điều này dường như khá phổ biến, vì vậy có thể sẽ xuất hiện trong một đề xuất khác trong tương lai gần. Tôi đồng ý rằng cách giải quyết này không phải là lý tưởng - cá nhân tôi cảm thấy việc mong đợi Optional(...)được nội suy vào chuỗi cho tùy chọn mạnh mẽ là điều hiển nhiên - đó chỉ thực sự là trường hợp của các IUO cần IMO cảnh báo này. Nhưng Swift không ngừng phát triển, vì vậy điều này có thể thay đổi sau này. Nhưng hiện tại, đó là những gì chúng tôi có.
Hamish

Tôi cũng tình cờ gặp một vấn đề có phần 'liên quan' trong hộp thoại if let not unboxing nữa tại đây stackoverflow.com/questions/42543512/… nếu bạn có thể xem qua? @Hamish
Stéphane de Luca

... trong trường hợp bất kỳ mã này là crazyness:guard result == nil else { print("result was \(result as Optional)") return }
loretoparisi

1
@loretoparisi Tại sao không sử dụng if let? tức là if let result = result { print("result was \(result)"); return }. Không phải tất cả việc trả lại sớm đều cần được thực hiện với lính canh.
Hamish

29

Hai cách dễ dàng hơn để giải quyết vấn đề này.

Lựa chọn 1:

Đầu tiên sẽ là bằng cách "buộc mở" giá trị bạn muốn trả lại bằng cách sử dụng một tiếng nổ (!)

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

Đầu ra:

5

Lựa chọn 2:

Cách khác, có thể là cách tốt hơn - là "mở gói an toàn" giá trị bạn muốn trả về.

var someValue: Int? = 5

if let newValue = someValue {
    print(newValue)
}

Đầu ra:

5

Bạn nên đi với tùy chọn 2.

Mẹo: Tránh ép buộc mở gói (!) Nếu có thể vì chúng tôi không chắc liệu chúng tôi sẽ luôn có giá trị cần mở.


1
Tôi mới nhưng tôi giống như phương án 2 để xác nhận các gói trước khi in và bạn luôn có một tùy chọn để in cái gì khác khi nó là quà nào
AbuTaareq

16

có vẻ như sử dụng Chuỗi (mô tả: tùy chọn) là đơn giản nhất.

giá trị mặc định ?? không có ý nghĩa đối với các chuỗi không phải là chuỗi, ví dụ Int.
Nếu Int là nil thì bạn muốn nhật ký hiển thị 'nil' không được mặc định thành Int khác, ví dụ 0.

Một số mã sân chơi để kiểm tra:

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

Đầu ra

optionalString: nil
optionalInt: nil

13

Sau khi cập nhật lên Xcode 8.3 và nhận được nhiều thông báo cảnh báo, tôi đã nghĩ ra cách sau giống với hành vi đầu ra ban đầu hơn, dễ dàng thêm vào, giảm bớt sự dài dòng khi sử dụng "Chuỗi (mô tả :)" cả trong mã và đầu ra .

Về cơ bản, hãy thêm một tiện ích mở rộng Tùy chọn cung cấp một Chuỗi mô tả thứ trong tùy chọn hoặc đơn giản là "nil" nếu không được đặt. Ngoài ra, nếu thứ trong tùy chọn là Chuỗi, hãy đặt nó trong dấu ngoặc kép.

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

Và cách sử dụng trong một sân chơi:

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"

Cảm ơn sự giúp đỡ từ liên kết sau:

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


Giải pháp này không hoạt động trong chuỗi tùy chọn. Thích a?.b?.c.orNil.
Vincent Sit

11

Xem bản sửa lỗi của Ole Begeman cho điều này . Tôi thích nó. Nó tạo một ???toán tử mà sau đó bạn có thể sử dụng như sau:

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"

5
Một tham chiếu đến bài viết trên blog của ông mô tả này sẽ hữu ích Tôi nghĩ: oleb.net/blog/2016/12/optionals-string-interpolation
Nicolai Henriksen

8

Nhấp đúp vào hình tam giác màu vàng hiển thị trên dòng chứa cảnh báo này. Điều này sẽ hiển thị FixIt với hai giải pháp.

Đã thêm ảnh chụp màn hình

  1. Sử dụng String(describing:)để tắt tiếng cảnh báo này:

    Sử dụng nó sẽ trở thành String(describing:<Variable>)

    Ví dụ. :String(describing: employeeName)

  2. Cung cấp một default valueđể tránh cảnh báo này:

    Sử dụng nó sẽ trở thành (<Variable> ?? default value)

    Ví dụ.: employeeName ?? “Anonymous” as! String


1
Có, tôi cũng sẽ tham gia Nhà điều hành Nil-Coalescing: developer.apple.com/library/content/documentation/Swift/…
kevinius

1
Câu trả lời chính xác! Nil-coalescing hoạt động tốt với điều này nếu bạn có một chuỗi giá trị thay thế để cung cấp
Lance Samaria

1

Swift 5

Giải pháp của tôi đang thực hiện một extensionmà Unwrap Optionalđối tượng Any.

Khi bạn ghi lại đối tượng hoặc in nó ra, bạn có thể thấy thực tế objecthoặc <nil>⭕️(kết hợp từ văn bản và ký tự trực quan). Nó hữu ích để xem xét, đặc biệt là trong nhật ký bảng điều khiển.

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

0

Tạo một phương thức nội suy chấp nhận một Kiểu chung tùy chọn với một tham số không tên. Tất cả các cảnh báo khó chịu của bạn sẽ biến mất một cách kỳ diệu.

extension DefaultStringInterpolation {
  mutating func appendInterpolation<T>(_ optional: T?) {
    appendInterpolation(String(describing: optional))
  }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.