简体   繁体   English

在数组为空时如何避免从API提取数据时应用崩溃

[英]How to avoid app crashing when pulling data from API when array is empty

I was checking my app, I tried to login and it login my account smoothly then suddenly it crashed and it shows an Fatal error: Index out of range appeared in this part of the code 我正在检查我的应用程序,尝试登录后顺利登录了我的帐户,然后突然崩溃了,并显示了致命错误:这部分代码中出现索引超出范围

completion(demographicsArray[0], nil)

Upon checking, the dumping process of the data in the back end is still on process that why the array on my end is empty, no data was pulled. 经过检查,后端中的数据转储过程仍在进行中,这就是为什么我这一端的数组为空,而没有数据被提取的原因。 How can I prevent the crashing of the app and how can I include alert message that will notify the user that their record is still on process? 如何防止应用程序崩溃以及如何添加警报消息,以通知用户其记录仍在处理中? Please help me out been solving this for a week but still I can't solve it. 请帮助我解决一个星期的问题,但仍然无法解决。 Codes are below for your references. 以下代码供您参考。 Thank you. 谢谢。

APIService.swift APIService.swift

 static func getPatientInformation(informationType: PatientInformationType, tokenType: String, token: String, hospitalNumber: String, completion: @escaping getPatientInformationTaskCompletion<Any>) {

        var patientInformationURL: URL!

        switch informationType {
            case .allergies:
                patientInformationURL = URL(string: "\(Endpoint.Patient.allergies)?hn=\(hospitalNumber)")
            case .demographics:
                patientInformationURL = URL(string: "\(Endpoint.Patient.demographics)?hn=\(hospitalNumber)")
            case .diagnosis:
                patientInformationURL = URL(string: "\(Endpoint.Patient.diagnosis)?hn=\(hospitalNumber)")
            case .medications:
                patientInformationURL = URL(string: "\(Endpoint.Patient.medications)?hn=\(hospitalNumber)")
        }

        guard patientInformationURL != nil else {
            completion(nil, .invalidURL)
            return
        }

        let header: HTTPHeaders = [
            "Authorization": "\(tokenType) \(token)",
            "Accept": "application/json"
        ]

        Alamofire.request(patientInformationURL, headers: header).responseJSON(completionHandler: { (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)

                    return
                }

                let decoder = JSONDecoder()

                switch (informationType) {
                case .allergies:
                    do {
                        let allergyArray = try decoder.decode([Allergies].self, from: jsonData)
                        completion(allergyArray, nil)
                    }catch {
                        completion(nil, .invalidJSON)
                    }
                case .demographics:
                    do {
                        let demographicsArray = try decoder.decode([Demographics].self, from: jsonData)
                            completion(demographicsArray.first, nil)
                        }catch {
                            completion(nil, .invalidJSON)
                    }

                case .diagnosis:
                    do {
                        let diagnosisArray = try decoder.decode([Diagnosis].self, from: jsonData)
                        completion(diagnosisArray, nil)
                    }catch {
                        completion(nil, .invalidJSON)
                    }
                case .medications:
                    do {
                        let medicationArray = try decoder.decode([Medication].self, from: jsonData)
                        completion(medicationArray, nil)
                    }catch {
                        completion(nil, .invalidJSON)
                    }
                }
            case 401:
                completion(nil, .unauthorizedToken)
            default:
                print("UNCAPTURED STATUS CODE FROM getPatientInformation\nSTATUS CODE: \(statusCode)")
                completion(nil, .uncapturedStatusCode)
            }
        })
    }

PatientProfileViewController.swift PatientProfileViewController.swift

func getPatientInfo() {
    guard let username = KeychainManager.getUsername(),
        let tokenType = KeychainManager.getTokenType(),
        let token = KeychainManager.getToken() else { return }

    SVProgressHUD.setDefaultMaskType(.black)
    SVProgressHUD.show(withStatus: "Retrieving Patient Information")

    APIService.Patients.getPatientInformation(informationType: .demographics,
                                              tokenType: tokenType, token: token,
                                              hospitalNumber: username) { (demographics, error) in

        guard let patientInformation = demographics as? Demographics, error == nil else {
            if let networkError = error {
                switch networkError {
                    case .noNetwork:
                        let popupDialog = PopupDialog(title: "No Network", message: "\(networkError.rawValue)")
                        popupDialog.addButton(DefaultButton(title: "OK", action: nil))
                        self.present(popupDialog, animated: true, completion: nil)
                    default:
                        let popupDialog = PopupDialog(title: "Error", message: "There is something went wrong. Please try again")
                        popupDialog.addButton(DefaultButton(title: "OK", action: nil))
                        self.present(popupDialog, animated: true, completion: nil)
                }
            }

            SVProgressHUD.dismiss()
            return
        }



        self.patientDemographics = patientInformation

        self.welcomeLabel.text = self.patientDemographics.displayName ?? "Welcome"

        self.patientInformationTableView.reloadData()
        SVProgressHUD.dismiss()
    }
}

You can always check if the array has enough elements before accessing it. 您始终可以在访问数组之前检查数组是否包含足够的元素。

if demographicsArray.count > 0 {
    completion(demographicsArray[0], nil)
} else {
    // handle empty array completion
}

Note: Why is your database returning data before processing it? 注意:为什么数据库在处理数据之前先返回数据?

I prefer use "guard" instead of "if" 我更喜欢使用“后卫”而不是“如果”

guard demographicsArray.count > 0 else {
  completion(nil, .noDemographicsAtPosition)
}

completion(resonseToSend, nil)

I think this way is more readable. 我认为这种方式更具可读性。

Advise: getPatientInformation has a lot of responsibilities, it would be great if you divide it into others functions like: 忠告:getPatientInformation承担很多责任,如果将其划分为其他函数,例如:

func getPatientInformationURL() -> String
func processResponse(completion: @escaping getPatientInformationTaskCompletion<Any>)

probably it became your code more readable, hope it helps you. 可能它使您的代码更具可读性,希望对您有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM