如何在 Realm 对象上建模 Swift 字典 属性?

How to model a Swift dictionary property on a Realm object?

我应该如何在 Realm 对象上为字典 属性 建模,以便在编码为 JSON 时我可以得到:

{
    "firstName": "John",
    "lastName": "Doe",
    "favoriteThings": {
        "car": "Audi R8",
        "fruit": "strawberries",
        "tree": "Oak"
    }
}

我尝试使用我在其他地方看到的 'key' 和 'value' 属性创建一个新对象 FavoriteThings...

public class Person: Object {
    @objc dynamic var firstName = ""
    @objc dynamic var lastName = ""
    var favoriteThings = List<FavoriteThings>()
}

但是当我将它编码为 JSON 时,List 自然而然地给了我一个数组。我不想要一个数组。我正在使用 Swift Codable。

{
    "firstName": "John",
    "lastName": "Doe",
    "favoriteThings": [
    {
      "key": "fruit",
      "value": "strawberries"
    },
    {
      "key": "tree",
      "value": "Oak"
    }
    ],
}

感谢任何指点!

贡萨洛

如您所知,列表默认编码为 json 数组。因此,要将列表编码为字典,您必须实现自定义编码方法才能做到这一点。

public class FavoriteThings: Object {
    @objc dynamic var key = ""
    @objc dynamic var value = ""

    convenience init(key: String, value: String) {
        self.init()
        self.key = key
        self.value = value
    }
}

public class Person: Object, Encodable {

    enum CodingKeys: String, CodingKey {
        case firstName
        case lastName
        case favoriteThings
    }

    @objc dynamic var firstName = ""
    @objc dynamic var lastName = ""
    let favoriteThings = List<FavoriteThings>()

    convenience init(firstName: String, lastName: String, favoriteThings: [FavoriteThings]) {
        self.init()
        self.firstName = firstName
        self.lastName = lastName
        self.favoriteThings.append(objectsIn: favoriteThings)
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(firstName, forKey: .firstName)
        try container.encode(lastName, forKey: .lastName)

        var favThings: [String: String] = [:]
        for thing in favoriteThings {
            favThings[thing.key] = thing.value
        }

        try container.encode(favThings, forKey: .favoriteThings)
    }
}

用法是这样的:

func testEncode() {
    let john = Person(
        firstName: "John",
        lastName: "Doe",
        favoriteThings: [
            .init(key: "car", value: "Audi R8"),
            .init(key: "fruit", value: "strawberries"),
            .init(key: "tree", value: "Oak"),
    ])

    let encoder = JSONEncoder()
    let data = try! encoder.encode(john)
    if let string = String(data: data, encoding: .utf8) {
        print(string)
    }
}

打印:

{"firstName":"John","favoriteThings":{"car":"Audi R8","fruit":"strawberries","tree":"Oak"},"lastName":"Doe"}