- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
在我的应用程序中,我需要从 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用于处理事件。就像遍历响应者链的事件一样,错误有可能使您的应用程序的抽象级别冒泡。根据错误的不同,您可能想要做一些与错误类型相关的事情。您的应用程序的不同组件可能需要了解错误,根据应用程序的状态,它可能不需要任何操作。
作为开发者,您最终知道错误会在何处影响您的应用以及如何影响。因此,鉴于我们如何选择实现技术解决方案。
我建议使用 Enumerations和 Closures至于构建我的错误处理解决方案。
这是一个 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/
对于 Metal ,如果对主纹理进行 mipmap 处理,是否还需要对多采样纹理进行 mipmap 处理?我阅读了苹果文档,但没有得到任何相关信息。 最佳答案 Mipmapping 适用于您将从中
我正在使用的代码在后端 Groovy 代码中具有呈现 GSP(Groovy 服务器页面)的 Controller 。对于前端,我们使用 React-router v4 来处理路由。我遇到的问题是,通过
我们正在 build 一个巨大的网站。我们正在考虑是在服务器端(ASP .Net)还是在客户端进行 HTML 处理。 例如,我们有 HTML 文件,其作用类似于用于生成选项卡的模板。服务器端获取 HT
我正在尝试将图像加载到 void setup() 中的数组中,但是当我这样做时出现此错误:“类型不匹配,'processing .core.PImage' does not匹配“processing.
我正在尝试使用其私有(private)应用程序更新 Shopify 上的客户标签。我用 postman 尝试过,一切正常,但通过 AJAX,它带我成功回调而不是错误,但成功后我得到了身份验证链接,而不
如何更改我的 Processing appIconTest.exe 导出的默认图标在窗口中的应用程序? 默认一个: 最佳答案 经过一些研究,我能找到的最简单的解决方案是: 进入 ...\process
我在 Processing 中做了一个简单的小游戏,但需要一些帮助。我有一个 mp3,想将它添加到我的应用程序中,以便在后台循环运行。 这可能吗?非常感谢。 最佳答案 您可以使用声音库。处理已经自带
我有几个这样创建的按钮: 在 setup() PImage[] imgs1 = {loadImage("AREA1_1.png"),loadImage("AREA1_2.png"),loadImage
我正在尝试使用 Processing 创建一个多人游戏,但无法弄清楚如何将屏幕分成两个以显示玩家的不同情况? 就像在 c# 中一样,我们有Viewport leftViewport,rightView
我一直在尝试使用 Moore 邻域在处理过程中创建元胞自动机,到目前为止非常成功。我已经设法使基本系统正常工作,现在我希望通过添加不同的功能来使用它。现在,我检查细胞是否存活。如果是,我使用 fill
有没有办法用 JavaScript 代码检查资源使用情况?我可以检查脚本的 RAM 使用情况和 CPU 使用情况吗? 由于做某事有多种方法,我可能会使用不同的方法编写代码,并将其保存为两个不同的文件,
我想弄清楚如何处理这样的列表: [ [[4,6,7], [1,2,4,6]] , [[10,4,2,4], [1]] ] 这是一个整数列表的列表 我希望我的函数将此列表作为输入并返回列表中没有重复的整
有没有办法在不需要时处理 MethodChannel/EventChannel ?我问是因为我想为对象创建多个方法/事件 channel 。 例子: class Call { ... fields
我有一个关于在 Python3 中处理 ConnectionResetError 的问题。这通常发生在我使用 urllib.request.Request 函数时。我想知道如果我们遇到这样的错误是否可
我一直在努力解决这个问题几个小时,但无济于事。代码很简单,一个弹跳球(粒子)。将粒子的速度初始化为 (0, 0) 将使其保持上下弹跳。将粒子的初始化速度更改为 (0, 0.01) 或任何十进制浮点数都
我把自己弄得一团糟。 我想在我的系统中添加 python3.6 所以我决定在我的 Ubuntu 19.10 中卸载现有的。但是现在每次我想安装一些东西我都会得到这样的错误: dpkg: error w
我正在努力解决 Rpart 包中的 NA 功能。我得到了以下数据框(下面的代码) Outcome VarA VarB 1 1 1 0 2 1 1 1
我将 Java 与 JSF 一起使用,这是 Glassfish 3 容器。 在我的 Web 应用程序中,我试图实现一个文件(图像)管理系统。 我有一个 config.properties我从中读取上传
所以我一直在Processing工作几个星期以来,虽然我没有编程经验,但我已经转向更复杂的项目。我正在编写一个进化模拟器,它会产生具有随机属性的生物。 最终,我将添加复制,但现在这些生物只是在屏幕上漂
有人知道 Delphi 2009 对“with”的处理有什么不同吗? 我昨天解决了一个问题,只是将“with”解构为完整引用,如“with Datamodule、Dataset、MainForm”。
我是一名优秀的程序员,十分优秀!