gpt4 book ai didi

ios - 在 Swift 中处理错误

转载 作者:IT王子 更新时间:2023-10-29 05:10:16 26 4
gpt4 key购买 nike

在我的应用程序中,我需要从 Web 下载一个 JSON 文件。我制作了一个 ResourceService 类,它有一个 download 方法,如下所示。我在我的应用程序的“更高级别”服务中使用此服务。您可以看到在下载过程中有很多地方可能出错。可能是服务器着火,暂时无法成功响应,也可能是临时文件移动过程中出现问题等。

现在,除了稍后尝试之外,用户可能对此无能为力。然而,他/她可能想知道出了点问题,下载或“更高级别”方法的行为无法成功。

我作为开发人员对此感到困惑,因为我不明白如何处理 Swift 中的错误。我有一个 completionHandler,如果有错误,它会接受一个错误,但我不知道我应该将哪种错误传回给调用者。

想法:

1) 如果我传递从 NSFileManager API 或 NSURLSession API 获得的错误对象,我会认为我正在将 download 方法的一些实现“泄露”给调用者。调用者如何根据错误知道预期的错误类型?可能两者兼而有之。

2) 如果我应该捕获并包装那些可能在 download 方法中发生的错误,那会是什么样子?

3) 如何处理方法内的多个错误源,以及调用可能抛出/返回 NSError 对象的方法的代码是什么样的?

作为调用者,您是否应该开始拦截您返回的错误,然后编写大量代码来根据错误代码区分消息/采取的操作?我根本不明白这个错误处理的东西,也不知道当一个方法中有很多事情可能出错时它会是什么样子。

func download(destinationUrl: NSURL, completionHandler: ((error: NSError?) -> Void)) {
let request = NSURLRequest(URL: resourceUrl!)

let task = downloadSession.downloadTaskWithRequest(request) {
(url: NSURL?, response: NSURLResponse?, error: NSError?) in

if error == nil {
do {
try self.fileManager.moveItemAtURL(url!, toURL: destinationUrl)
} catch let e {
print(e)
}
} else {
}
}.resume()
}

最佳答案

首先,这是一个很好的问题。错误处理是一项特定任务,适用于一系列令人难以置信的情况,谁知道会对您的应用程序状态产生什么影响。关键问题是什么对您的用户、应用和开发者您有意义。

我喜欢在概念上将其视为 Responder chain用于处理事件。就像遍历响应者链的事件一样,错误有可能使您的应用程序的抽象级别冒泡。根据错误的不同,您可能想要做一些与错误类型相关的事情。您的应用程序的不同组件可能需要了解错误,根据应用程序的状态,它可能不需要任何操作。

作为开发者,您最终知道错误会在何处影响您的应用以及如何影响。因此,鉴于我们如何选择实现技术解决方案。

我建议使用 EnumerationsClosures至于构建我的错误处理解决方案。

这是一个 ENUM 的人为示例。如您所见,它代表了错误处理解决方案的核心。

    public enum MyAppErrorCode {

case NotStartedCode(Int, String)
case ResponseOkCode
case ServiceInProgressCode(Int, String)
case ServiceCancelledCode(Int, String, NSError)

func handleCode(errorCode: MyAppErrorCode) {

switch(errorCode) {
case NotStartedCode(let code, let message):
print("code: \(code)")
print("message: \(message)")
case ResponseOkCode:
break

case ServiceInProgressCode(let code, let message):
print("code: \(code)")
print("message: \(message)")
case ServiceCancelledCode(let code, let message, let error):
print("code: \(code)")
print("message: \(message)")
print("error: \(error.localizedDescription)")
}
}
}

接下来我们要定义我们的 completionHandler,它将替换 ((error: NSError?) -> Void) 您在下载方法中的闭包。

((errorCode: MyAppErrorCode) -> Void)

新的下载功能

func download(destinationUrl: NSURL, completionHandler: ((errorCode: MyAppErrorCode) -> Void)) {
let request = NSURLRequest(URL: resourceUrl!)

let task = downloadSession.downloadTaskWithRequest(request) {
(url: NSURL?, response: NSURLResponse?, error: NSError?) in

if error == nil {
do {
try self.fileManager.moveItemAtURL(url!, toURL: destinationUrl)
completionHandler(errorCode: MyAppErrorCode.ResponseOkCode)

} catch let e {
print(e)
completionHandler(errorCode: MyAppErrorCode.MoveItemFailedCode(170, "Text you would like to display to the user..", e))

}


} else {
completionHandler(errorCode: MyAppErrorCode.DownloadFailedCode(404, "Text you would like to display to the user.."))

}
}.resume()
}

在您传入的闭包中,您可以调用 handleCode(errorCode: MyAppErrorCode) 或您在 ENUM 上定义的任何其他函数。

您现在拥有了定义您自己的错误处理解决方案的组件,该解决方案易于针对您的应用进行定制,并且您可以使用它来将 http 代码和任何其他第三方错误/响应代码映射到您应用中有意义的内容。您还可以选择让 NSError 冒泡是否有用。


编辑

回到我们的设计。

我们如何处理与 View Controller 的交互?我们可以选择像现在这样的集中机制,或者我们可以在 View Controller 中处理它并将范围保持在本地。为此,我们会将逻辑从 ENUM 移动到 View Controller ,并针对 View Controller 任务的非常具体的要求(在本例中为下载),您也可以将 ENUM 移动到 View Controller 的范围。我们实现了封装,但最终很可能会在项目的其他地方重复我们的代码。无论哪种方式,您的 View Controller 都必须对错误/结果代码做一些事情

我更喜欢的一种方法是让 View Controller 有机会处理完成处理程序中的特定行为,或者/然后将其传递给我们的 ENUM 以获得更一般的行为,例如发送下载已完成的通知、更新应用程序状态或只是通过“确定”的单个操作抛出 AlertViewController。

我们通过向我们的 View Controller 添加方法来实现这一点,这些方法可以传递 MyAppErrorCode ENUM 和任何相关变量(URL、请求...)并添加任何实例变量来跟踪我们的任务,即不同的 URL,或者我们放弃尝试下载之前的尝试次数。

这是在 View Controller 处理下载的可能方法:

func didCompleteDownloadWithResult(resultCode: MyAppErrorCode, request: NSURLRequest, url: NSURL) {

switch(resultCode) {
case .ResponseOkCode:
// Made up method as an example
resultCode.postSuccessfulDownloadNotification(url, dictionary: ["request" : request])

case .FailedDownloadCode(let code, let message, let error):

if numberOfAttempts = maximumAttempts {
// Made up method as an example
finishedAttemptingDownload()

} else {
// Made up method as an example
AttemptDownload(numberOfAttempts)
}

default:
break

}
}

关于ios - 在 Swift 中处理错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34364986/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com