【问题标题】:Load two json files of Arrays of Dictionaries. Add missing dictionaries from the file A to file B加载两个字典数组的 json 文件。将文件 A 中缺少的字典添加到文件 B
【发布时间】:2019-03-14 02:08:21
【问题描述】:

我需要同步两个 json 文件,以便在应用更新后将新内容从 File A(位于 app bundle 中)添加到 File B

两个 json 文件都是字典数组。我需要从 File A 中迭代字典,并根据“id”值,如果 File B 中不存在字典,我需要附加那些缺失的字典并将文件B保存回文件系统。

我在下面有一个解决方案可以做到这一点,并且似乎有效。但是实在是太丑了!当然,我在大约 15 分钟内完成了这个工作,但我确信必须有更好的方法来处理这个问题。另外,我不想通过将这些字典转换为结构或模型进行比较来进一步混淆水域,只是为了将它们转换回字典-> json。

这里的任何建议都会很棒!我更喜欢干净的代码,但这是一团糟。

typealias JSON = [[String: Any]]
static private func uglySync() {
    let fileName: String = "someFileName"
    guard let sourceUrl = Bundle.main.url(forResource: fileName, withExtension: "json") else { return }
    guard let destinationDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
    let destinationUrl = destinationDirectory.appendingPathComponent("Data/" + fileName + ".json")

    do {
        let sourceData = try Data(contentsOf: sourceUrl)
        do {
            if let sourceArray = try JSONSerialization.jsonObject(with: sourceData, options: .mutableContainers) as? JSON {
                do {
                    let destinationData = try Data(contentsOf:  destinationUrl)
                    do {
                        if let destinationArray = try JSONSerialization.jsonObject(with: destinationData, options: .mutableContainers) as? JSON {
                            var mutableArray = destinationArray
                            sourceArray.forEach({ (item) in
                                if let itemId = item["id"] as? String {
                                    let foundItem = destinationArray.filter { $0["id"] as! String == itemId }.first
                                    if foundItem == nil {
                                        mutableArray.append(item)
                                    }
                                }
                            })

                            do {
                                let jsonData = try JSONSerialization.data(withJSONObject: mutableArray, options: .prettyPrinted)
                                try jsonData.write(to: destinationUrl)
                            } catch let error as NSError {
                                print("Couldn't write to file: \(error.localizedDescription)")
                            }
                        } else {
                            print("Cound not process json")
                        }
                    } catch {
                        print(error.localizedDescription)
                    }
                } catch {
                    print(error.localizedDescription)
                }
            } else {
                print("Cound not process json")
            }
        } catch {
            print(error.localizedDescription)
        }
    } catch {
        print(error.localizedDescription)
    }

    // oh wow the try catches :/
}

【问题讨论】:

    标签: arrays json swift dictionary


    【解决方案1】:

    我已将文件分组转换为 jsonArray 以简化 do...catch。或者,如果您不需要打印错误消息,您可以选择使用 Optional try? 以及删除 do...catch 块。

    typealias JSONArray = [[String: Any]]
    
    private func jsonArray(from fileURL: URL) -> JSONArray? {
        do {
            let fileData: Data = try Data(contentsOf: fileURL)
            guard let jsonArray = (try JSONSerialization.jsonObject(with: fileData, options: .mutableContainers)) as? JSONArray else {
                debugPrint("Failed to find JSON Array table")
                return nil
            }
    
            return jsonArray
        } catch {
            print(error.localizedDescription)
            return nil
        }
    }
    
    func sync() {
        let fileName: String = "someFileName"
    
        guard
            let fileURL: URL = Bundle.main.url(forResource: fileName, withExtension: "json"),
            let destinationDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first,
            let destinationURL: URL = destinationDirectory.appendingPathComponent("Data/" + fileName + ".json"),
            let sourceArray = jsonArray(from: fileURL),
            let destinationArray = jsonArray(from: destinationURL)
        else {
            return
        }
    
        var mutableArray = destinationArray
        let destinationIDArray = destinationArray.compactMap { $0["id"] as? String }
    
        mutableArray.forEach { (item) in
            if let itemId = item["id"] as? String, !(destinationIDArray.contains { $0 == itemId }) {
                mutableArray.append(item)
            }
        }
    
        // Update File
        do {
            let jsonData = try JSONSerialization.data(withJSONObject: mutableArray, options: .prettyPrinted)
            try jsonData.write(to: destinationURL)
        } catch {
            print("Couldn't write to file: \(error.localizedDescription)")
        }
    }
    

    【讨论】:

    • 我真的很喜欢这个解决方案!我已将此添加到我的项目中,经过一些小调整后效果很好。干净且易于阅读。谢谢!
    【解决方案2】:

    我认为您可以将不同的trys 放在同一个do 块中。

    do {
      try function1()
      try function2()
    } catch {
      print(error.localizedDescription)
    }
    

    所以之后你的函数可能看起来像

        typealias JSON = [[String: Any]]
        static private func moderatelyOkSync() {
            let fileName: String = "someFileName"
            guard let sourceUrl = Bundle.main.url(forResource: fileName, withExtension: "json") else { return }
            guard let destinationDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
            let destinationUrl = destinationDirectory.appendingPathComponent("Data/" + fileName + ".json")
    
            do {
                let sourceData = try Data(contentsOf: sourceUrl)
                if let sourceArray = try JSONSerialization.jsonObject(with: sourceData, options: .mutableContainers) as? JSON {
                    let destinationData = try Data(contentsOf:  destinationUrl)
                }
                var mutableArray = destinationArray
                sourceArray.forEach({ (item) in
                    if let itemId = item["id"] as? String {
                        let foundItem = destinationArray.filter { $0["id"] as! String == itemId }.first
                        if foundItem == nil {
                            mutableArray.append(item)
                        }
                    }
                })
                let jsonData = try JSONSerialization.data(withJSONObject: mutableArray, options: .prettyPrinted)
                try jsonData.write(to: destinationUrl)
    
            } catch {
                print(error.localizedDescription)
            }
    
        }
    

    【讨论】:

    • 非常正确。我有点啰嗦。您对加载/比较/保存方面有何看法?感谢您的快速回复!
    • @mejim707 保存和加载看起来也不错,可能会将其提取到单独的函数中。比较也不算太寒酸。
    【解决方案3】:

    我会这样做的方法是使用 struct 解码 json 文件,然后将其编码(序列化)到其他文件。因为执行此操作的代码将是 2 行,但您首先必须在结构中布局所有变量。可能还不是最优的

    【讨论】:

      猜你喜欢
      • 2015-03-21
      • 1970-01-01
      • 1970-01-01
      • 2018-10-19
      • 2015-06-24
      • 1970-01-01
      • 1970-01-01
      • 2015-08-26
      • 2012-07-19
      相关资源
      最近更新 更多