存储可解码到 Realm 但数组始终为空

Storage decodable to the Realm but the array always empty

现在我正在使用 Decodable 解析 JSON 并存储到 Realm,这里是 JSON 数据

{
    "DefaultCompositionItem":[
            {"Serial":1,"Category_Id":5,"Count":1,"Composition_Id":1},
            {"Serial":2,"Category_Id":2,"Count":7,"Composition_Id":1},
            {"Serial":3,"Category_Id":2,"Count":7,"Composition_Id":1},
            {"Serial":4,"Category_Id":2,"Count":4,"Composition_Id":1},
            {"Serial":5,"Category_Id":2,"Count":4,"Composition_Id":1},
            {"Serial":6,"Category_Id":3,"Count":7,"Composition_Id":1},
            {"Serial":7,"Category_Id":4,"Count":7,"Composition_Id":1}
            ],
    "Serial":1,
    "Case_Id":1,
    "Name":"組合A",
    "Price":760
}

问题是: 我无法从此 JSON 获取 DefaultCompositionItem 数组。 我正在使用名为 fetchComposition 的方法从服务器获取数据,获取 [Composition] 并使用 insertComposition 方法

插入到 Realm
func fetchComposition(from url: String, complete: @escaping (Bool, [Composition], APIError?) -> ()) {
    Alamofire.request(url).responseData { (response) in
        guard let data = response.result.value else {
            return complete(false, [Composition](), APIError.unknownError(response.error?.localizedDescription ?? "Unknown"))
        }

        let decoder = JSONDecoder()
        do {
            let items = try decoder.decode([Composition].self, from: data)

            complete(true, items, nil)
        } catch {
            complete(true, [Composition](), APIError.unknownError(error.localizedDescription))
        }
    }
}

func insertComposition(composition: Composition) {

    try! realm.write {
        print("Starting storing...")
        // Composition
        let compositionEntity = Composition()

        compositionEntity.id = composition.id
        compositionEntity.caseID = composition.caseID
        compositionEntity.name = composition.name
        compositionEntity.price = composition.price

        // DefaultItem
        let defaultItems = composition.items

        defaultItems.forEach({ (i) in
            print(i.categoryID)  // print nothing
        })
        defaultItems.forEach({ item in
            let newItem = DefaultCompositionItem()
            newItem.itemID = item.itemID
            newItem.categoryID = item.categoryID
            newItem.compositionID = item.compositionID
            newItem.count = item.count
            compositionEntity.items.append(newItem)
        })

        realm.add(compositionEntity)
    }
}

领域对象Composition:

final class Composition:Object, Decodable {

    @objc dynamic var id: Int = 0
    @objc dynamic var name: String = ""
    @objc dynamic var caseID: Int = 0
    @objc dynamic var price: Double = 0.0

    let items = List<DefaultCompositionItem>()


    override static func primaryKey() -> String? {
        return "id"
    }

    private enum RootKeys: String, CodingKey {
        case DefaultCompositionItem
        case Serial
        case Name
        case CaseId = "Case_Id"
        case Price
    }

    convenience init(from decoder: Decoder) throws {
        self.init()
        let container = try decoder.container(keyedBy: RootKeys.self)
        id = try container.decode(Int.self, forKey: .Serial)
        name = try container.decode(String.self, forKey: .Name)
        caseID = try container.decode(Int.self, forKey: .CaseId)
        price = try container.decode(Double.self, forKey: .Price)
        if let itemArray = try container.decodeIfPresent(List<DefaultCompositionItem>.self, forKey: .DefaultCompositionItem) {
        items.append(objectsIn: itemArray)
    }

    }
}


final class DefaultCompositionItem:Object, Decodable {

    @objc dynamic var itemID: Int = 0
    @objc dynamic var categoryID: Int = 0
    @objc dynamic var compositionID: Int = 0
    @objc dynamic var count: Int = 0


    private enum ItemKeys: String, CodingKey {
        case Serial
        case CategoryId = "Category_Id"
        case CompositionId = "Composition_Id"
        case Count
    }

    override static func primaryKey() -> String? {
        return "itemID"
    }

    convenience init(from decoder: Decoder) throws {
        self.init()
        let itemContainer = try decoder.container(keyedBy: ItemKeys.self)
        itemID = try itemContainer.decode(Int.self, forKey: .Serial)
        categoryID = try itemContainer.decode(Int.self, forKey: .CategoryId)
        compositionID = try itemContainer.decode(Int.self, forKey: .CompositionId)
        count = try itemContainer.decode(Int.self, forKey: .Count)
    }
}

extension List: Decodable {

    public convenience init(from decoder: Decoder) throws {
        self.init()
    }
}

问题是您分配给 Compositionitems 属性 而不是像需要的那样改变它。 Realm's documentation explicitly calls out List<T> 属性应该使用 let 而不是 var 来声明以避免这个问题。

items 更改为使用 let 声明,然后通过 修改 现有的 items 值而不是分配给它。

我还建议解码为 DefaultCompositionItem 的数组,而不是 List<DefaultCompositionItem>,因为 List<T> 对 Swift 的 Decodable 一无所知.