Как работать с ответами от API, который может содержать массив или словарь? - PullRequest
1 голос
/ 04 октября 2019

У меня есть вызов API, который проверяет UserLogin и пароль и отправляет ответ, основываясь на правильности пар имени пользователя и пароля.

API возвращает словарь, если пара имя пользователя-парольневерный и массив словарей, если имя пользователя-пароль верны.

Проблема, с которой я сталкиваюсь, заключается в том, что я не могу уменьшить ответ от Alamofire на определенный тип данных.

   func afLoginDriver(firstName: String,password:String,completion: @escaping ([Dictionary<String, Any>])->Void){
    let driverLoginURL = "URL here.."
    let parameters = ["firstName" : firstName, "Password" : password]
    AF.request(driverLoginURL, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: nil).responseJSON { response in

        switch response.result {
            case .success:
                let driverLoginResponse = response.value as? [Dictionary<String, Any>]
                completion(driverLoginResponse)
            break
        case .failure(let error):
            print(error)
        }
    }
}

Переменная driverLoginResponse выдает ошибку, если пары имя пользователя-пароль неверны, так как это всего лишь словарь, а не массив словаря.

Я попытался использовать оператор guard let, но все еще не смог получить эторабота.

Ответы [ 2 ]

2 голосов
/ 04 октября 2019

Я бы использовал Codable и enum для этого, но учтите следующее:

Сначала реализуйте enum с любым возможным ответом:

enum LoginDriverResponseValue {
    case dictionary([String: Any])
    case array([[String: Any]])
    case string(String)
    case unknown(Any)
}

, затем изменитесигнатура функции для адаптации с этим перечислением:

func afLoginDriver(firstName: String, password: String, completion: @escaping (LoginDriverResponseValue)->Void) {
,,,
}

И, наконец, включите перечисление и вызовите соответствующее завершение:

guard let responseValue = response.value else { return }

switch responseValue {
case let result as [String: Any]: completion(.dictionary(result))
case let result as [[String: Any]]: completion(.array(result))
case let result as String: completion(.string(result))
default: completion(.unknown(responseValue))
}

- Более инкапсулированный способ:

youможет инкапсулировать определение типа responseValue в enum LoginDriverResponseValue:

extension LoginDriverResponseValue {
    init(responseValue: Any) {
        switch responseValue {
        case let result as [String: Any]: self = .dictionary(result)
        case let result as [[String: Any]]: self = .array(result)
        case let result as String: self = .string(result)
        default: self = .unknown(responseValue)
        }
    }
}

Таким образом, единственное, что вам нужно в функции, будет:

guard let responseValue = response.value else { return }
completion(LoginDriverResponseValue(responseValue: responseValue))
2 голосов
/ 04 октября 2019
  1. Приведите значения ответа к потенциальным типам и обработайте каждый из них:
if let responseOne = response.value as? [String: Any] {
    // ...
} else if let responseTwo = response.value as? [[String: Any]] {
    // ...
}

Вы можете использовать Codable:
struct Response: Codable {
   var valueOne: [String: Any]?
   var valueTwo: [[String: Any]]?
}

...