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

标签 ios json swift realm codable

现在我正在使用 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)
    }
}

Realm 对象组成:

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 outList<T>应使用 let 声明属性而不是 var来避免这个问题。

更改 items使用 let 声明,然后通过改变 items 的现有值来修复由此产生的编译错误而不是分配给它。

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

关于ios - 存储可解码到 Realm 但数组始终为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48179201/

相关文章:

ios - 从当前 View Controller 打开一个新的 ViewController

c# - 使用 Newtonsoft.Json c# 序列化数组

python - python中字符串前的 'u'是什么意思?

ios - 使 UITextView 高度动态化,约束乘数问题

ios - 获取带有经纬度的城市和国家名称(iOS)

objective-c - 如何更改 Apple 示例代码项目 MoviePlayer

ios - 当将一行插入到SQL Server表中时,如何触发向移动设备的推送通知?

ios - 长时间触摸时增加跳跃高度,直到最大高度

iphone - 如何在 iPhone 应用程序上进行纹理控制?

sql - 如何在postgresql中将两行转换为键值json对象?