我有一个JSON响应(下面(,我需要解析它-
[
{
"id":123,
"name":"Fahim Rahman",
"age":25,
"friends":[
{
"firstName": "Imtiaz",
"lastName": "Khan",
"avatar_url": null
}
],
"groups":{
"xcet":{
"name":"xcek cert etsh tnhg",
"createdDate":"2022-10-31T10:00:48Z"
},
"juyt":{
"name":"jfd uyt you to",
"createdDate":"2021-09-13T10:00:00Z"
},
"some random key":{
"name": "some name",
"createdDate":"2026-03-27T10:00:00Z"
}
}
}
]
为了在我的代码中解析它,我创建了这个模型。我无法解析组,因为这不是一个列表,而是一个对象-
import ObjectMapper
class Person: BaseObject {
@objc dynamic var ID: Int = -1
@objc dynamic var name: String = ""
@objc dynamic var age: Int = -1
var friendsList = List<Friends>()
override func mapping(map: ObjectMapper.Map) {
ID <- map["id"]
name <- map["name"]
age <- map["age"]
friendsList <- map["friends"]
}
}
class Friends: BaseObject {
@objc dynamic var firstName: String = ""
@objc dynamic var lastName: String = ""
@objc dynamic var avatarURL: String = ""
override func mapping(map: ObjectMapper.Map) {
firstName <- map["firstName"]
lastName <- map["name"]
avatarURL <- map["avatar_url"]
}
}
我知道这是一个糟糕的JSON。组应该在列表中,而不是嵌套对象,但不幸的是,我得到了这个响应。
这里,在组的响应中,嵌套对象的数量是动态的,并且嵌套对象的键也是动态的。因此,我无法将其解析为friends属性。
所以我的问题是,我如何绘制";组";?
在映射组之前,我们需要一个类,它可以将每个组与其密钥(即xct(一起保存
例如
Class Groups: BaseObject {
@objc dynamic var key: String = ""
@objc dynamic var value: GroupsItem?
convenience init(key: String, value: GroupsItem) {
self.init()
self.key = key
self.value = value
}
}
Class GroupsItem: BaseObject {
@objc dynamic var name: String?
@objc dynamic var createdDate: String?
...
}
然后在你的Person类中,你可以将其映射为-
private func mapGroupsItems(map: ObjectMapper.Map) -> List<GroupsItem> {
var rowsDictionary: [String: Groups]?
rowsDictionary <- map["groups"]
let rows = List<GroupsItem>()
if let dictionary = rowsDictionary {
for (key, value) in dictionary {
rows.append(GroupsItem(key: key, value: value))
}
}
return rows
}
不要忘记从映射调用这个方法-
override public func mapping(map: ObjectMapper.Map) {
...
groups = mapGroupsItems(map: map)
}
尝试这种方法,对Groups
使用自定义init(from decoder: Decoder)
,对我来说效果很好。对非SwiftUI系统使用类似的方法。
struct ContentView: View {
@State var people: [Person] = []
var body: some View {
ForEach(people) { person in
Text(person.name)
ForEach(Array(person.groups.data.keys), id: .self) { key in
Text(key).foregroundColor(.red)
Text(person.groups.data[key]?.name ?? "no name").foregroundColor(.blue)
Text(person.groups.data[key]?.createdDate ?? "no date").foregroundColor(.blue)
}
}
.onAppear {
let json = """
[
{
"id":123,
"name":"Fahim Rahman",
"age":25,
"friends":[
{
"firstName": "Imtiaz",
"lastName": "Khan",
"avatar_url": null
}
],
"groups":{
"xcet":{
"name":"xcek cert etsh tnhg",
"createdDate":"2022-10-31T10:00:48Z"
},
"juyt":{
"name":"jfd uyt you to",
"createdDate":"2021-09-13T10:00:00Z"
},
"some random key":{
"name": "some name",
"createdDate":"2026-03-27T10:00:00Z"
}
}
}
]
"""
if let data = json.data(using: .utf8) {
do {
self.people = try JSONDecoder().decode([Person].self, from: data)
print("---> people: (people)")
} catch {
print("decode error: (error)")
}
}
}
}
}
struct Person: Identifiable, Codable {
let id: Int
var name: String
var age: Int
var friends: [Friend]
var groups: Groups
}
struct Friend: Codable {
var firstName, lastName: String
var avatarURL: String?
enum CodingKeys: String, CodingKey {
case firstName, lastName
case avatarURL = "avatar_url"
}
}
struct Info: Codable {
var name: String
var createdDate: String
}
struct Groups: Identifiable, Codable {
let id = UUID()
var data: [String:Info] = [:]
init(from decoder: Decoder) throws {
do {
let container = try decoder.singleValueContainer()
self.data = try container.decode([String:Info].self)
} catch {
print(error)
}
}
}
您的模型类结构将是
// MARK: - Welcome7Element
struct Welcome7Element {
let id: Int
let name: String
let age: Int
let friends: [Friend]
let groups: Groups
}
// MARK: - Friend
struct Friend {
let firstName, lastName: String
let avatarURL: NSNull
}
// MARK: - Groups
struct Groups {
let xcet, juyt, someRandomKey: Juyt
}
// MARK: - Juyt
struct Juyt {
let name: String
let createdDate: Date
}
感谢@shakif_的深刻回答。以下是我如何基于这个答案来解决这个问题-
import ObjectMapper
import RealmSwift
class Person: BaseObject {
@objc dynamic var ID: Int = -1
@objc dynamic var name: String = ""
@objc dynamic var age: Int = -1
var friendsList = List<Friends>()
var groups = List<Group>
override func mapping(map: ObjectMapper.Map) {
ID <- map["id"]
name <- map["name"]
age <- map["age"]
friendsList <- map["friends"]
groups = extractGroups(map)
}
private func extractGroups(_ map: ObjectMapper.Map) -> List<Group> {
let items = List<Group>()
var modifiedJSON = [String: Group]
modifiedJSON <- map["groups"]
for (key,value) in modifiedJSON {
let item = GroupMapper(key: key, value: value)
if let group = item.value {
items.append(group)
}
}
return items
}
}
class Friends: BaseObject {
@objc dynamic var firstName: String = ""
@objc dynamic var lastName: String = ""
@objc dynamic var avatarURL: String = ""
override func mapping(map: ObjectMapper.Map) {
firstName <- map["firstName"]
lastName <- map["name"]
avatarURL <- map["avatar_url"]
}
}
class Group: BaseObject {
@objc dynamic var name: String = ""
@objc dynamic var createdDate: String = ""
override func mapping(map: ObjectMapper.Map) {
name <- map["name"]
createdDate <- map["createdDate"]
}
}
struct GroupMapper {
var key: String = ""
var value: Group?
}