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

时间:2019-01-21 00:33:49

标签: ios arrays swift

我正在检查我的应用,尝试登录后顺利登录我的帐户,然后突然崩溃了,并显示了致命错误:索引超出范围出现在代码的这一部分

completion(demographicsArray[0], nil)

检查后,后端数据的转储过程仍在进行中,这就是为什么我端的数组为空,没有数据被拉出的过程。如何防止应用程序崩溃以及如何添加警报消息,以通知用户其记录仍在处理中?请帮助我解决一个星期的问题,但仍然无法解决。 以下代码供您参考。谢谢。

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

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()
    }
}

2 个答案:

答案 0 :(得分:0)

您始终可以在访问数组之前检查数组是否具有足够的元素。

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

注意:为什么数据库在处理数据之前先返回数据?

答案 1 :(得分:0)

我更喜欢使用“后卫”而不是“如果”

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

completion(resonseToSend, nil)

我认为这种方式更具可读性。

建议:getPatientInformation承担很多责任,如果将其划分为其他函数,例如:

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

可能它使您的代码更具可读性,希望对您有所帮助。