如何在 swift 中将 JSON `null` 值传递给`nil` 值?

Posted

技术标签:

【中文标题】如何在 swift 中将 JSON `null` 值传递给`nil` 值?【英文标题】:How to pass JSON `null` value to `nil` value in swift? 【发布时间】:2019-08-02 03:42:01 【问题描述】:

我有这个json,其中hospitalNumber 有值,并且有实例返回null 值。 hospitalNumber 具有重要意义,因为它是 API 中端点所需参数的一部分。请看样例json:


  "responseMessage": "Request successful",
  "data": [
    
      "hospitalNumber": null,
      "patientName": "Manual Entry",
      "totalAmount": 10339.8000,
      "manualEntry": true
    ,
    
     "hospitalNumber": "1111111",
     "patientName": "test patient",
     "totalAmount": 932.5000,
    "manualEntry": false
   
 ]

下面是我的 APIService,它将拉取上面的 json

typealias getPatientDetailsPerPayoutTaskCompletion = (_ patientDetailsPerPayout: [PatientPayoutDetails]?, _ error: NetworkError?) -> Void

 //Patient procedure details per patient
 //parameterName is .searchByHospitalNumber = "hospitalNumber"
    static func getPatientDetailsPerPayout(periodId: Int, doctorNumber: String, parameterName: PatientParameter, hospitalNumber: String, manualEntry: Bool, completion: @escaping getPatientDetailsPerPayoutTaskCompletion) 


        guard let patientDetailsPerPayoutURL = URL(string: "\(Endpoint.Patient.patientProcedureDetails)?periodId=\(periodId)&doctorNumber=\(doctorNumber)\(parameterName.rawValue)\(hospitalNumber)&manualEntry=\(manualEntry)") else 

            completion(nil, .invalidURL)
            return
        

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

        Alamofire.request(patientDetailsPerPayoutURL, method: .get, encoding: JSONEncoding.default).responseJSON  (response) in
            print(patientDetailsPerPayoutURL)
            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)
                    return
                

                let decoder = JSONDecoder()

                do 
                    let patientDetailsPayout = try decoder.decode(RootPatientPayoutDetails.self, from: jsonData)
                    if (patientDetailsPayout.data?.isEmpty)! 
                        completion(nil, .noRecordFound)
                     else 
                    completion(patientDetailsPayout.data, nil)
                    
                 catch 
                    completion(nil, .invalidJSON)
                

            case 400: completion(nil, .badRequest)
            case 404: completion(nil, .noRecordFound)
            default:
                print("**UNCAPTURED STATUS CODE FROM (getPatientDetailsPayout)\nSTATUS CODE: \(statusCode)")
                completion(nil, .uncapturedStatusCode)
            
        
    

getPatientPayoutDetails 函数

 func getPerPatientPayoutDetails(from: String, manualEntry: Bool) 
    //SVProgressHUD.setDefaultMaskType(.black)
    //SVProgressHUD.setForegroundColor(.white)
    SVProgressHUD.setBackgroundColor(.lightGray)
    SVProgressHUD.show(withStatus: "Retrieving Patient Procedures")

    APIService.PatientList.getPatientDetailsPerPayout(periodId: doctorPayoutWeek[3].periodId!, doctorNumber: doctorNumber, parameterName: .selectedByHospitalNumber, hospitalNumber: from, manualEntry: manualEntry)  (patientPayout, error) in

        guard let patientPerPayoutDetails = patientPayout, 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))
                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)
                
            

            SVProgressHUD.dismiss()
            return
        
        self.selectedPatientPayment = patientPerPayoutDetails
        print(self.selectedPatientPayment)
        SVProgressHUD.dismiss()
        return
    

表格视图

 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 

    switch indexPath.section 
    case 0: break
    case 1: break
    case 2:

        filteredPatient = indexPath.row
        let selectedpatient = patientList[filteredPatient].hospitalNumber
        let selectedEntry = patientList[filteredPatient].manualEntry
        self.isBrowseAll = false
        getPerPatientPayoutDetails(from: selectedpatient!, manualEntry: selectedEntry)
    default: break
    

hospitalNumber 为 nil 时需要 null 字符串的端点

https://sample.com/openapi/getpatientpayoutdetails?periodId=579&doctorNumber=2866&hospitalNumber=null&manualEntry=true

如您所见,医院编号对于端点具有重要作用。我的问题是,一旦 tableView 重新加载它会正确显示数据,但是当我 didSelect cellnull hospitalNumber 时,我的应用程序崩溃并显示 Found nil error 自 @987654338 @ 具有 null 值。希望您理解我要解释的内容,请帮助我。谢谢你

【问题讨论】:

如果您不确定是否会获得某个键的确定值,请在您的 Codable 模型中将该变量设置为 optional。和don't force unwrap,使用guard-let/if-let @SharadChauhan 我有这个 `struct Patient: Codable var hospitalNumber: String? var 患者姓名:字符串? var totalAmount: Double var manualEntry: Bool enum CodingKeys: String, CodingKey case hospitalNumber = “hospitalNumber” case patientName = “patientName” case totalAmount = “totalAmount” case manualEntry = “manualEntry” 如果 hospitalNumber 是 nil,预期的行为是什么?顺便说一句,didSelect 中的switch 太过分了。只需检查if indexPath.section == 2 filteredPatient = indexPath.row ... @vadian 如果hospitalNumbernil。它应该返回null 值。因为端点应该是这样的https://sample.com/openapi/getpatientpayoutdetails?periodId=579&doctorNumber=2866&hospitalNumber=null&manualEntry=true 【参考方案1】:

您的Codable 模型是正确的,您只需要guard-let/if-let 即可防止崩溃:

if let selectedpatient = patientList[filteredPatient].hospitalNumber, let selectedEntry = patientList[filteredPatient].manualEntry 
   self.isBrowseAll = false
   getPerPatientPayoutDetails(from: selectedpatient, manualEntry: selectedEntry)

更新: 如果你想在 nil 的情况下创建 endPoint 也可以使用 coalescing operator

getPerPatientPayoutDetails(from: selectedpatient ?? "null", manualEntry: selectedEntry)

【讨论】:

我试过你的答案,我的应用程序没有崩溃,但是当我打印manualEntryFlag 的值时,为什么值从true 更改为false。哪个是我应该得到参数的实际值 没有代码可以更改manualEntryFlag 的值,所以您可能需要再次正确地检查该值。【参考方案2】:

在 didSelect 中做喜欢

let selectedpatient:String!  //or Int whatever type it is right not this line initializes selected patient with nil 
//below line will check for nil and ALSO NULL if NULL or nil it will not reassigne selectedpatient which means  selectedpatient will remain nil 
 if let hsptlNbr =  patientList[filteredPatient].hospitalNumber as? yourDataType
    selectedpatient =  hsptlNbr

在此之后,如果在下面的方法中存在,您可以将其作为 nil 或值传递

getPerPatientPayoutDetails(from: selectedpatient, manualEntry: selectedEntry)

更改func getPerPatientPayoutDetails(from: String, manualEntry: Bool)

func getPerPatientPayoutDetails(from: String?, manualEntry: Bool)

【讨论】:

您的意思是String??因为情况正好相反。如果不设置值,这段代码会崩溃。 @titus 设置 getPerPatientPayoutDetails(from: String? from as optional :) 不会崩溃 或者是的,他可以用作 let selectedpatient:String? 它会崩溃。当您使用 ! 隐式展开一个值时。你告诉编译器它不是nil。所以当你尝试阅读它时,如果它是nil,它会崩溃。

以上是关于如何在 swift 中将 JSON `null` 值传递给`nil` 值?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 中将 JSON 写入 Realm

如何在 Swift 中将 JSON 转换为数据类型?

如何在 Swift 中将 Realm 对象转换为 JSON?

如何在 Swift 中将数组添加到我的 JSON 字典

如何在swift中将json数组保存和检索到用户默认值?

如何在 Swift 中将 JSON 数据保存到 UserDefault? [复制]