将无效网址解码为nil

Ash*_*lls 2 url swift codable

在您回答之前:

我意识到:

  • 空字符串是无效的 URL
  • 我可以写一个定制的解码器 Employee
  • 我可以宣布urlString

我正在寻找一种更好的解决方案,用于解码可选项URL本身。我希望Codable我缺少一些魔法!


所以,我有JSON之类的

let json = Data("""
                {
                    "name": "Fred",
                    "url": ""
                }
                """.utf8)
Run Code Online (Sandbox Code Playgroud)

以及包含可选URL的相应​​对象…

struct Employee: Decodable {
    let name: String
    let url: URL?
}
Run Code Online (Sandbox Code Playgroud)

由于urlJSON中的内容无效,因此我希望将其解码为nil,而不是抛出错误。

尝试以下操作不起作用(不会被调用)…

extension Optional where Wrapped == URL {
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        do {
            self = try container.decode(URL.self)
        } catch {
            self = nil
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

过去我用过……

struct FailableDecodable<T: Decodable>: Deodable {

    let wrapped: T?

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        do {
            self.wrapped = try container.decode(T.self)
        } catch {
            print("Error decoding failable object: \(error)")
            self.wrapped = nil
        }
    }
}

struct Employee: Decodable {
    let name: String
    let url: FailableDecodable<URL>?
}
Run Code Online (Sandbox Code Playgroud)

但这需要我不断提及url.wrapped

有更好的解决方案吗?

rra*_*ael 5

如果您使用的是Swift 5.1,则可以使用@propertyWrapper

let json = """
{
    "name": "Fred",
    "url": ""
}
""".data(using: .utf8)!


@propertyWrapper
struct FailableDecodable<Wrapped: Decodable>: Decodable {
    var wrappedValue: Wrapped?

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        wrappedValue = try? container.decode(Wrapped.self)
    }
}

struct Employee: Decodable {
    let name: String

    @FailableDecodable
    private(set) var url: URL?
}

let employee = try! JSONDecoder().decode(Employee.self, from: json)
employee.url // nil
Run Code Online (Sandbox Code Playgroud)