Загрузите два файла JSON из массивов словарей.Добавить недостающие словари из файла A в файл B - PullRequest
0 голосов
/ 14 марта 2019

Мне нужно синхронизировать два файла json, чтобы добавить новый контент из Файл A (находится в комплекте приложения) в Файл B после обновления приложения.

Оба файла JSON являются массивами словарей.Мне нужно перебрать форму словаря Файл A и, основываясь на значении "id", если словарь отсутствует в Файл 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 :/
}

Ответы [ 3 ]

1 голос
/ 14 марта 2019

Я сгруппировал преобразование файлов в jsonArray, чтобы упростить do ... catch.В качестве альтернативы, если вам не нужно печатать сообщение об ошибке, вы можете также выбрать Необязательный 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)")
    }
}
0 голосов
/ 14 марта 2019

Я бы сделал это, чтобы декодировать файлы json с помощью struct, а затем кодировать (сериализовать) их в другие файлы. Потому что код для этого будет 2-х строчным, но сначала вам нужно будет расположить все переменные в структуре. Вероятно, все еще не оптимально

0 голосов
/ 14 марта 2019

Я думаю, вы можете поместить различные try s в один и тот же блок 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)
        }

    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...