簡體   English   中英

在Alamofire中使用get請求時,如何快速修復無效的JSON響應?

[英]How to fix invalid JSON response in swift when using get request in Alamofire?

我正在創建一個應用程序,其中它從API Server中提取PatientList ,並將其顯示到TableView 經過檢查后,它返回200狀態代碼,但落入invalidJSON錯誤。 但是當我簽入Postman時 ,它返回200狀態代碼並正確提取記錄。 我很困惑我的代碼的哪一部分會導致錯誤,因為我是新手。 我正在尋求幫助以解決該問題。 以下是我的示例代碼供您參考。 提前非常感謝您。

Patient.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"
   }
}

APIService.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)
                }
            }
        }

Controller.swift

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

    }
}

JSON回應

[
   {
   "hospitalNumber": null,
   "patientName": null,
   "totalAmount": 31104
   },
   {
   "hospitalNumber": "",
   "patientName": "LastName, FirstName",
   "totalAmount": 3439.8
   }
]

您的JSON響應顯示,某些字段可以為空-至少hospitalNumberpatientName 此外, hospitalNumber是JSON中的字符串-感謝@Don指出。 您的struct還應該能夠通過使映射字段也可以為空來應對這些可為空的情況。

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

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

如果totalAmount也可以為null,則需要執行相同的totalAmount 當然,在任何情況下API是否正確返回空值都是另一個問題-可能需要解決空醫院號或醫院名稱如何有用的問題。

確保在使用它們時不要強行拆開它們。

只需在模型類中進行以下更改。 將模型類變量定義為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)
    }
}

注意:

如果相同密鑰的類型不同,或者您可以說該類型不同於指定的類型,則Codable OR Decodable

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM