简体   繁体   English

从 Swift 中的 JSON 数组中解析有效对象

[英]Parse valid objects from JSON array in Swift

I have a codable struct like this我有一个像这样的可编码结构

struct User: Codable {
    let id: String
    let registrationId: String
    let firstName: String?
    let lastName: String?
}

Now, the response from the server contains an array like this现在,来自服务器的响应包含一个这样的数组

 [
  {
    "id": "1",
    "registrationId": "r1",
    "firstName": "Jon",
    "lastName": "Doe"
  },
  {
    "id": "2",
    "registrationId": null,
    "firstName": null,
    "lastName": null
  },
  {
    "id": "3",
    "registrationId": null,
    "firstName": null,
    "lastName": null
  },
  {
    "id": "4",
    "registrationId": "r4",
    "firstName": "Jon",
    "lastName": "Snow"
  }
]

I want to parse this as [User] but only those who have a valid(not null) registrationId .我想将其解析为 [User] 但只有那些具有有效(非空) registrationId的人。 I know how to parse JSON in swift.我知道如何在 swift 中解析 JSON。 But the problem here is because of the two invalid data in the middle the whole response will run into decoding error.但是这里的问题是由于中间的两个无效数据,整个响应会遇到解码错误。 But I want to parse it as an array of [User] containing valid ones(in this case first and last object).但我想将它解析为一个包含有效对象的[User]数组(在这种情况下是第一个和最后一个对象)。

Any hints or help is much appreciated.非常感谢任何提示或帮助。

1- Make registrationId an optional 1-将registrationId设为可选

 let registrationId: String?

2- 2-

 let res = try JSONDecoder().decode([User].self,from:data)
 let filtered = res.filter { $0.registrationId != nil }

after all, this data must come from a database or an array.毕竟,这些数据必须来自数据库或数组。 By making the id parameter as the primary key, the registrationId parameter as a foreign key, and if you are working on the registrationId parameter, you can make a productive sequence or if it is on the array, you can link the method that generates the sequence for that registrationId.通过将id参数作为主键,registrationId参数作为外键,如果你正在处理registrationId参数,你可以创建一个生产序列,或者如果它在数组上,你可以链接生成的方法该registrationId的序列。

Now I know how to achieve this.现在我知道如何实现这一目标了。

struct User: Codable {
    let id: String
    let registrationId: String
    let firstName: String?
    let lastName: String?
}

struct WrappedDecodableArray<Element: Decodable>: Decodable {
    let elements: [Element]

    init(from decoder: Decoder) throws {
        var container = try decoder.unkeyedContainer()
        var elements = [Element]()
        while !container.isAtEnd {
            if let element = try? container.decode(Element.self) {
                elements.append(element)
            } else {
                // move the container currentIndex forward
                _ = try container.decode(Block.self)
            }
        }
        self.elements = elements
    }

    private struct Block: Decodable {}
}

func testUserParsing() {
    let jsonStr = """
    [
      {
        "id": "1",
        "registrationId": "r1",
        "firstName": "Jon",
        "lastName": "Doe"
      },
      {
        "id": "2",
        "registrationId": null,
        "firstName": null,
        "lastName": null
      },
      {
        "id": "3",
        "registrationId": null,
        "firstName": null,
        "lastName": null
      },
      {
        "id": "4",
        "registrationId": "r4",
        "firstName": "Jon",
        "lastName": "Snow"
      }
    ]
    """

    let jsonData = jsonStr.data(using: .utf8)!
    let wrappedArray = try! JSONDecoder().decode(WrappedDecodableArray<User>.self, from: jsonData)
    print(wrappedArray.elements)
}

It would have been more elegant if we could override the init(from decoder: Decoder) for Array under certain conditions like extension Array where Element == User .如果我们可以在某些条件下(例如extension Array where Element == User )覆盖 Array 的init(from decoder: Decoder)会更优雅。 But looks like this is not possible.但看起来这是不可能的。 Initializer inside the extension can not override the original one and hence never get called.扩展内的初始化程序不能覆盖原来的初始化程序,因此永远不会被调用。 So for now looks like wrapping with a struct is the only solution.所以现在看起来用结构包装是唯一的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM