我正在解码来自API的响应,当我有期望的数据时,它就可以工作. 但是服务器通常会以{}{}\n来响应,这是一个空对象.这是意料之中的.

在try 解码预期数据之前,我希望捕捉这些响应.

我采用了下面的方案,但我觉得应该有一种更有原则的方法来解码空json对象.

    let empty1 = "{}".data(using: .utf8)!
    let empty2 = "{}\n".data(using: .utf8)!

    let (data, response) = try await URLSession.shared.data(for: request)
    if data == empty1 || data == empty2 {
        print("empty json response")
        return nil
    }

    // what I would like to do
    let decoded = try JSONDecoder().decode(xxxx, from: data)  // what to decode here
    
    // how to test for emptyness

我还可以比较数据的String表示,但这与我当前的方案是一样的.

推荐答案

我假设您希望JSONDecoder().decode调用在数据不为空时抛出一个错误.你可以通过

  • 创建一个自定义编码密钥,可以代表JSON中的任何密钥
  • 得到由上述键控的键控解码容器
  • 判断解码容器是否包含任何密钥—如果包含,则JSON不为空.
struct EmptyJSON: Decodable {
    struct AnyKey: CodingKey {
        var stringValue: String
        
        init?(stringValue: String) {
            self.stringValue = stringValue
        }
        
        var intValue: Int?
        
        init?(intValue: Int) {
            self.intValue = intValue
            self.stringValue = "\(intValue)"
        }
        
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: AnyKey.self)
        if !container.allKeys.isEmpty {
            throw CustomDecodingError.shouldBeEmpty
        }
    }

    enum CustomDecodingError: Error {
        case shouldBeEmpty
    }
}

然后你可以这样做:

if let decoded = try? JSONDecoder().decode(EmptyJSON.self, from: data) {
    // JSON is empty
} else {
    // JSON is not empty
}

这也会将JSON数组视为"空".您可以捕获特定错误以获得更多的控制

do {
    try JSONDecoder().decode(EmptyJSON.self, from: data)
    // empty object
} catch EmptyJSON.CustomDecodingError.shouldBeEmpty {
    // non-empty object
} catch {
    // something else, e.g. array (both empty and non-empty), string, number
}

Swift相关问答推荐

SWIFT异步/等待,多个监听程序

如何使用Swift宏和@Observable和@Environment?

如何隐藏集合视图中特定的单元格,以避免出现空白空间?

设备上ScrollView为什么会将内容高度更改为随机值,而在预览上不会? - 优化后的标题:设备上ScrollView内容高度随机变化问题解决

带有可选字符串作为键路径的 SwiftUI iOS16 表

允许为 self 分配新的 struct 值的理由是什么?

在 SwiftUI 中将属性显式设置为其默认值

我如何遵守与演员的协议?

并发执行代码中捕获的 var 的变异

在 Vapor 4 中使用协议的通用流利查询

ZStack 中的 ProgressView 与 View 的行为不同

如何在 SwiftUI 的 fileImporter 中为 allowedContentTypes 设置 xcodeproj 类型?

.onTapGesture 不适用于 Stepper,仅适用于其文本

如何仅将 SwiftUI 不透明度应用于父视图?

在 Swift 中强制崩溃的最简单方法

subscribeOn 和 observeOn 的顺序重要吗?

由于编译器中的内部保护级别,无法访问框架 init 中的公共 struct

<<错误类型>> 奇怪的错误

迭代 Firebase 中的子快照

从 Swift 初始化程序调用方法