Проверьте наличие ключа объекта JSON перед приведением к Codable в Swift 4 - PullRequest
0 голосов
/ 17 октября 2018

API моей компании .... уникален.Единственное, что составляет 100%, - это то, что все ответы инкапсулированы в объекте myCompany .И затем либо в объекте Данные , либо в объекте Ошибки .После этого это довольно честная игра.Я работаю с нашим главным разработчиком API, но это медленное изменение, потому что код был написан 10 лет назад и т. Д. И т. Д.

{ "myCompany": {
        "Errors": [{
            //Various error message key/values based upon who ever created it
        }]
    }
}


{ "myCompany": {
        "Data": {
            //any key/value of arrays and objects that I want to turn into a Codable
        }
    }
}

Можно ли мне проверить, является ли ключ корневого уровнясуществует до того, как я попробую JSON Decode в Codeable Struct?Я надеюсь, что это имеет смысл.

Например, если данные json имеют ключ корневого уровня jsonData["myCompany"]["Data"], а MySpecialClass - это то, что запрашивало, я мог бы просто отправить значение jsonData["myCompany"]["Data"] MySpecialClass , так что он может декодировать JSON

let mydata = try? JSONDecoder().decode(MySpecialClassData.self, from: jsonData["myCompany"]["Data"])

Это было в Objective-C, я мог просто проверить ключи в словаре, чтобы выполнить это.Я еще не знаю этого в Swift.

do {
    guard let jsonData = try JSONSerialization.jsonObject(with: urlSessionDataTaskResponse, options: [.allowFragments]) as? [[String:Any]] else  {
    print("Error jsonData was not in the correct format. Surprise. Surprise.");
    if let str = String(data: dataResponse, encoding: String.Encoding.utf8) {
        print("Raw Data: \(str)")
    }
        return
    }

    // Something like this
    // if   jsonData["myCompany"]["Data"]     
    // else if  jsonData["myCompany"]["Errors"]     
    // else who knows throw an error            

  ///I have tried But this doesn't seem to work
 guard let myCompany = jsonData["myCompany"] as? [String:Any] else { return }

} catch {
    print("ERROR: \(error)")
}

Все учебники, которые я видел, требуют, чтобы я поместил данные в Codable перед тем, как что-либо делать.

Любоймысли?

Ответы [ 3 ]

0 голосов
/ 17 октября 2018

Ваш ответ - это словарь [String: Any], но вы пытаетесь расшифровать его с помощью словарного массива [[String: Any]].Внутри вашего ответа есть еще один словарь с ключом «Ошибки» или «Данные» в зависимости от ситуации.

guard let jsonData = try JSONSerialization.jsonObject(with: urlSessionDataTaskResponse, options: [.allowFragments]) as? [String:Any] else  {
print("Error jsonData was not in the correct format. Surprise. Surprise.");
if let str = String(data: dataResponse, encoding: String.Encoding.utf8) {
        print("Raw Data: \(str)")
    }
    return
}
if let myCompany = jsonData["myCompany"] as? [String : Any]{
    if let data = myCompany["Data"] as? [Any]{
        //you get your data
    }
    else if let errors = myCompany["Errors"] as? [Any]{
        //you get your errors
    }
}
} catch {
print("ERROR: \(error)")
}

Это должно работать.

0 голосов
/ 08 апреля 2019

закодировать данные в словарь:

extension Encodable {
    var dictionary: [String: Any]? {
        guard let data = try? JSONEncoder().encode(self) else { return nil}
        return (try? JSONSerialization.jsonObject(with: data, options: .allowFragments)).flatMap{ $0 as? [String: Any]}
    }
}

получить отражение нашего объекта:

protocol DataProtocol: Codable {
    func getMirror() -> Mirror
}
extension DataProtocol {
    func getMirror() -> Mirror {
        return Mirror(reflecting: self)
    }
}

// some object:
struct dateModal: DataProtocol {
    var name: String?
    var age: Int?
}

//return false if key not found in json:
private func keyValidation<T: DataProtocol>(with dataModel: T?) -> Bool {
    guard let dictionaryModel = dataModel.dictionary, let mirror = dataModel?.getMirror() else { return false }
    for attr in mirror.children {
        guard dictionaryModel[attr.label ?? ""] != nil else { return false }
    }
    return true
}

//decode the data:

.....
let dataModel = try JSONDecoder().decode(AnyClass, from: data)

//then check for the key:

guard keyValidation(with: dataModel) else { return }
0 голосов
/ 17 октября 2018

В случае, если вы правильно построили Error и Data, вы можете использовать оба из них внутри родительского struct в качестве опций и декодировать их, ваш код может выглядеть следующим образом

struct ParentResponse: Codable {
data: MySpecialClassData?
error: MySpecialErrorData?  // or an array of it would be like this [MySpecialErrorData]?

}

Теперь вы можете декодировать это ParentResponse и проверить, был ли декодирован data или нет, проверив, является ли его значение nil просто необязательной цепочкой.

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