在Alamofire中使用get请求时,如何快速修复无效的JSON响应?

时间:2019-05-14 03:34:38

标签: ios swift rest api alamofire

我正在创建一个应用程序,其中它从API服务器提取viewModel.itemClickedEvent.observe(this, Observer {isItemClicked-> if(isItemClicked){ // Do your changes } }) ,并且将显示为PatientList。检查后,它返回TableView状态代码,但出现200错误。但是,当我签入 Postman 时,它会返回invalidJSON状态代码并正确提取记录。我很困惑我的代码的哪一部分会导致错误,因为我是新手。我正在寻求帮助以解决该问题。以下是我的示例代码供您参考。提前非常感谢您。

Patient.swift

200

APIService.swift

struct Patient: Codable {
    let hospitalNumber: Int
    let patientName: String
    let totalAmount: Double

enum CodingKeys: String, CodingKey {
    case hospitalNumber = "hospitalNumber"
    case patientName = "patientName"
    case totalAmount = "totalAmount"
   }
}

Controller.swift

struct PatientList {
    typealias getPatientListTaskCompletion = (_ patientListperPayout: [Patient]?, _ error: NetworkError?) -> Void


    static func getPatientList(doctorNumber: Int, periodId: Int, completion: @escaping getPatientListTaskCompletion) {

        guard let patientPerPayoutURL = URL(string: "\(Endpoint.Patient.patientPerPayout)?periodId=\(periodId)&doctorNumber=\(doctorNumber)") else {
            completion(nil, .invalidURL)
            return
        }

        let sessionManager = Alamofire.SessionManager.default
        sessionManager.session.getAllTasks { (tasks) in
            tasks.forEach({ $0.cancel() })
        }

        Alamofire.request(patientPerPayoutURL, method: .get, encoding: JSONEncoding.default).responseJSON { (response) in
            guard HelperMethods.reachability(responseResult: response.result) else {
                completion(nil, .noNetwork)
                return
            }

            guard let statusCode = response.response?.statusCode else {
                completion(nil, .noStatusCode)
                return
            }

            switch(statusCode) {
            case 200:
                guard let jsonData = response.data else{
                    completion(nil, .invalidJSON)
                    print(statusCode)
                    return
                }

                let decoder = JSONDecoder()

                do {
                    let patientListArray = try decoder.decode([Patient].self, from: jsonData)
                    let sortedPatientListArray = patientListArray.sorted(by: { $0.patientName < $1.patientName })
                    completion(sortedPatientListArray, nil)
                }catch{
                    completion(nil, .invalidJSON)
                    print(statusCode)
                }
            case 400:
                completion(nil, .badRequest)
            case 404:
                completion(nil, .noRecordFound)
            default:
                print("UNCAPTURED STATUS CODE FROM getPatientList\nSTATUS CODE: \(statusCode)")
                completion(nil, .uncapturedStatusCode)
                }
            }
        }

JSON响应

var patientList: [Patient]! {
    didSet {
       performSegue(withIdentifier: patientListIdentifier, sender: self)
    }
}

override func viewDidLoad() {
    super.viewDidLoad()

    self.latestCreditedAmountTableView.dataSource = self
    self.latestCreditedAmountTableView.delegate = self

    configureTableViewCell()
    showTotalCreditedAmount()
     getDoctorPayoutSummary(doctorNumber: doctorNumber)

}

func getDoctorPayoutSummary(doctorNumber: Int) {
  self.payoutSummary = payoutSummaryDetails
        self.taxRateVatRateLabel.text = "\(self.payoutSummary.taxRate) / \(self.payoutSummary.vatRate)"
        self.getPatientList()
        self.latestCreditedAmountTableView.reloadData()
        return
}

 func getPatientList() {

    APIService.PatientList.getPatientList(doctorNumber: doctorNumber, periodId: currentRemittance.periodId) { (patientListArray, error) in
        guard let patientListPerPayout = patientListArray, error == nil else {
            if let networkError = error {
                switch networkError {
                case .noRecordFound:
                    let alertController = UIAlertController(title: "No Record Found", message: "You don't have current payment remittance", preferredStyle: .alert)
                    alertController.addAction(UIAlertAction(title: "OK", style: .default))
                    self.present(alertController, animated: true, completion: nil)
                case .noNetwork:
                    let alertController = UIAlertController(title: "No Network", message: "\(networkError.rawValue)", preferredStyle: .alert)

                    alertController.addAction(UIAlertAction(title: "OK", style: .default))
                    self.present(alertController, animated: true, completion: nil)
                default:
                    let alertController = UIAlertController(title: "Error", message: "There is something went wrong. Please try again", preferredStyle: .alert)
                    alertController.addAction(UIAlertAction(title: "OK", style: .default))
                    self.present(alertController, animated: true, completion: nil)
                }
            }
            return
        }

        self.patientList = patientListPerPayout

        return

    }
}

2 个答案:

答案 0 :(得分:1)

您的JSON响应表明,某些字段可以为空-至少if (!ModelState.IsValid) { return OnGet(); } if ($num_rows > 0 ) { print "<table border=0>"; while ( $a_row = mysqli_fetch_row($result) ) { print "<tr>\n"; foreach ($a_row as $field) print "\t<td>$field</td>\n"; print "\t<td><a href='cart.php?id=$your_product_id'>Add to cart</a></td>\n"; print "</tr>"; } print "</table>"; } hospitalNumber也是JSON中的字符串-感谢@Don指出。您的patientName还应该能够通过使映射的字段也可以为空来应对这些可为空的情况。即

hospitalNumber

如果struct也可以为null,则需要执行相同的操作。当然,在任何情况下API是否正确返回空值都是另一个问题-可能需要解决空医院号或医院名称的作用。

请确保在使用字段时不要强行打开它们。

答案 1 :(得分:0)

只需在模型类中进行以下更改。将模型类变量定义为optional,这不是API所必需的。

struct Patient: Codable {
    var hospitalNumber: String?
    let patientName: String?
    let totalAmount: Double?

    enum CodingKeys: String, CodingKey {
        case hospitalNumber = "hospitalNumber"
        case patientName = "patientName"
        case totalAmount = "totalAmount"
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        if let hospitalNumb = try container.decode(Int?.self, forKey: .hospitalNumber) {
            hospitalNumber = String(hospitalNumb)
        } else {
            hospitalNumber = try container.decode(String.self, forKey: .hospitalNumber)
        }
        patientName = try container.decode(String.self, forKey: .patientName)
        totalAmount = try container.decode(Double.self, forKey: .totalAmount)
    }
}

注意:

CodableDecodable不起作用,如果同一键的类型不同,或者您可以说该类型不同于指定的类型。