Tag: 错误处理

开始进行Swift编程第14部分-错误处理

在上一篇文章中,我们讨论了泛型。 开始Swift编程第13部分-泛型 以前,我们介绍了类型别名,属性观察器以及“自我vs自我”。 medium.com 这是很难获得的信息,但这就是我们练习的原因。 仅仅因为我写了这个系列来进行教学,并不意味着这足以让您掌握所教的一切。 您可能从我的一篇文章转到另一篇相关文章,但我不会反对您。 事实上,我鼓励您继续从不同的来源学习。 我感谢通过阅读和/或鼓掌阅读每篇文章的人们所表现出的忠诚度,但我的首要目标不是要获得人气。 这是为了确保当您完成我的一篇文章时,您学到了一些新知识。 无需赘言,我们开始。 您是否曾经去过厨房准备食物并意识到没有干净的盘子? 您有几种选择: A.放弃晚餐 B.到餐厅去,或者 C.洗碗,然后在家修理晚餐 这些决定不仅影响您,而且影响您所喂养的人们。 选项A是最简单的解决方案,但每个人都饿着肚子,看着你成为晚餐的救星。 选项B也很容易,但价格昂贵,需要做一些不必要的额外工作,而且味道并不总是像家庭自制菜那样好。 选项C是一条艰难的道路,但如果您希望自己的食物品尝到自己想要的口味而又少有抱怨,并且希望没有破损的菜肴,那它就是最好的解决方案。 那么,所有这些与错误处理有什么关系? 一切! 当您决定尝试晚餐时,您调用了一种方法。 那么我们如何抛出错误呢? 可以通过在函数声明中的参数之后附加throws来引发错误。 但是,如果我们想从抛出函数返回错误字符串怎么办? 我们有一个选择,我之前已经暗示过。 为我们提供了针对Apple的所有错误的localizedDescription ,但它不仅神奇地读取了文本fileOpenError并提出了“无法打开文件”文本。 我们必须告诉它要提供什么。

有效的iOS错误管理

曾几何时,王国中有一个很棒的App。 该应用程序非常复杂,并包含许多晦涩难懂的部分,但它给使用它的所有用户带来了极大的欢乐。 但是,有一天,一个邪恶的错误出现了,并向王国的App用户显示了一个难看且难以理解的错误代码。 一位勇敢的开发人员被要求杀死龙来修复该错误,并且得到的票差不多是这样的: “用户无法继续购买-有时会出现一个奇怪的错误,有时什么也没有发生。” 勇敢的开发者拿起他的键盘,然后…忽略了该错误,删除了整个代码库,并重新编写了Swift 5中的所有内容。 再也没有看到错误代码,从此以后他们都过着幸福的生活。 结束。 不幸的是,现实生活中没有这样的童话。 存在错误,作为开发人员,您的任务是了解问题并加以解决。 现在,让我们看一下最常见的问题和iOS应用程序中通常如何处理错误的不足之处。 当应用失败并没有任何反应时,这可能意味着某个时刻丢失了一个或多个错误。 例如: 虽然这种方法的一些负面结果可能看起来很明显,但其他一些则更加模棱两可。 显而易见的是:用户屏幕上出现难看且难以理解的错误消息 这些错误消息显然不是针对用户的。 这些对用户可见的唯一结果是在App Store中有许多不良评论。 模棱两可:重要信息的丢失 相同的低级(网络/解析/核心数据)错误可能会以多种不同方式影响您的应用。 如果仅传播原始错误,则介于两者之间的所有信息都将丢失,不被记录或跟踪,最终调试该错误将变得更加困难。 对于用户而言,这些不希望的结果以及代码的完整性可以并且应该避免。 或者,如何以标准且一致的方式传播错误。 错误管理始终是任何应用程序的重要组成部分,甚至更重要的是,如果您的应用程序分为内部Pod,开发Pod,开放源Pod,库,实用程序和内部框架。 在整篇文章中,我们将这些依赖项称为“ 模块 ”。 在Just Eat,我们探索了Swift / Objective-C代码库的几种选择。 最后,我们选择继续使用经典的常绿NSError和NSUnderlyingErrorKey Universe,这是一种特别在macOS中使用的方法,自平台诞生之初就由Apple提出。 在介绍建议的解决方案之前,让我们先介绍几个关键概念。 如官方文档和NSHipster在本文中所述,NSError对象由以下内容组成: 错误域 -表示“错误上下文”或错误来源的字符串。 错误代码 -表示错误的Int值。 错误创建者有责任使其有意义。 不同的域可以具有完全不同的含义的相同错误代码。 用户信息字典 -包含有关错误的所有其他有用信息的字典。 错误链是NSError的链接列表。 每个错误都使用标准键NSUnderlyingErrorKey将先前的错误嵌入到用户信息字典中。 您可以将其视为标准链接列表。 如下所示。 我们汇总了一组准则,以统一我们在所有应用程序的各个部分,模块和库中进行错误管理的方法。 最终结果是一个一致的代码库 传播 展示架 日志 应用中生成的任何错误。 这意味着从应用程序用户界面收到的最终错误结构如下所示: […]

iOS:在Swift中重新添加关键字

Rethrows是您在Swift中很少遇到的关键字之一。 在本文中,我们将尝试以一种简单的方式来解释它,而无需太多文献😉 我们将Rethrows用于可能会或不会引发错误的方法(取决于其功能参数) 在拥有Rethrows关键字(Swift 2)之前,我们必须复制函数“ doSomething”以支持两种情况。 那就是所有的朋友。 感谢您阅读并继续编写良好的代码👍

斯威夫特:尝试,尝试?,尝试! 和“双重可选”。

Swift引入了比目标C更好,更简单的错误处理方法。您可以使用swift关键字throws标记一个方法,这意味着该方法可能会引发错误,调用者必须根据需要进行处理。 枚举UserNameError:错误{ 案例userIdNotExist } func getNameOfUser(userId uid:Int)引发->字符串{如果uid == 0 { 返回“亚历克斯” }否则,如果uid == 1 { 返回“杰克” } if uid == 2 { 返回“吉尔” 抛出UserNameError.userIdNotExist } 在此示例中,方法getNameOfUser仅处理3个getNameOfUser 。 对于其他userId,它将引发错误。 现在让我们看看如何使用Try , Try! 和Try? 用于调用此方法。 尝试 您可以通过两种方式使用它。 第一个是使用try / catch调用时捕获错误。 func callerMethod(){做{让名字=尝试getNameOfUser(userId:1)}捕获{ //处理错误 } } ..或确保,调用方方法标记为throws ,将错误传递给调用链。 func callerMethod()抛出{让名字=尝试getNameOfUser(userId:1)} 尝试? 这是最新的功能。 它返回一个可选值,并在调用成功后成功展开。 如果出现任何错误,它将返回nil 。 func callerMethod(){让名称=尝试? getNameOfUser(userId:1)} […]

在Swift中处理非可选选项

可选参数可以说是Swift最重要的功能之一,也是将其与Objective-C之类的语言区分开来的关键。 通过被迫处理可能 nil ,我们倾向于编写更具可预测性和较少错误的代码。 但是,有时可选参数会使您陷入困境,因为程序员如您所知(或者至少您是在这种假设下 ),即使使用某个变量,某些变量也总是非零。可选类型。 就像在视图控制器中处理视图时一样: 在这种情况下,Swift程序员将在几乎与制表符和空格相同的程度上存在分歧。 有人说: “由于它是可选的,因此您应该始终使用what或guard let适当地解开它。” 而其他人会朝完全不同的方向说: “由于您知道该变量不会为nil,请强制将其解包(使用!)。 崩溃比最终处于不确定状态要好。” 基本上,我们在这里谈论的是是否进行防御性编程。 我们是否试图从不确定的状态中恢复,还是仅仅放弃并崩溃? 如果我不得不对这个问题给出一个二进制答案,那么我绝对会选择后者。 未定义状态会导致很难发现错误,可能会导致不必要的代码执行,而采用防御性编程只会导致难以推理的代码。 但是,我宁愿不必给出二进制答案,而是研究一些可用于以更细微的方式解决此问题的技术。 让我们潜入吧! 真的可选吗? 变量和属性是可选的,但实际上是程序逻辑所必需的,实际上是体系结构缺陷的征兆。 如果需要某些东西,直到没有它会使您处于未定义状态–它不应是可选的。 尽管在某些情况下(例如与某些系统API进行交互时),确实很难避免使用可选选项-在许多情况下,我们可以使用某些技术来摆脱可选选项。 懒惰胜于非可选的 一种避免使用属性的可选选项的方法是通过使用惰性属性,该属性需要在创建父对象之后创建值(例如,视图控制器中的视图,应在loadView()或viewDidLoad() )。 惰性属性可以是非可选的,但仍不需要在其父级的初始化程序中创建。 它将在首次访问时创建。 让我们从之前更新TableViewController ,以为其tableView使用惰性属性: 没有可选项,没有不确定的状态! 🎉 适当的依赖项管理比非可选的可选项更好 可选项的另一个常见用法是打破循环依赖关系。 有时您会遇到A依赖于B ,但B也依赖于A 。 像这样的设置: 正如我们在上面看到的,我们在UserManager和CommentManager之间具有循环依赖关系,其中它们都不假定彼此拥有所有权,但是它们在逻辑上仍然CommentManager 。 那只是等待发生的错误! 😅 为了解决上述问题,我们改为让CommentComposer充当中间人,并负责通知UserManager和CommentManager已经作出评论: 这样, UserManager可以保留对CommentManager的强引用,而无需任何保留(或依赖)周期: 我们再次删除了所有可选内容,并提供了可预测的代码! 🎉 优雅地崩溃 在上面的示例中,我们看到了一些示例,在这些示例中,我们可以调整代码以通过删除可选项来消除不确定性。 但是,有时这是不可能的。 假设您正在加载包含应用程序配置的本地JSON文件。 这本质上是一个可能失败的操作,因此我们将需要添加一些错误处理。 如果配置无法加载,则继续执行程序会使应用程序处于未定义状态,因此在这种情况下最好崩溃。 这样,我们可以获得崩溃报告,并希望我们的测试和质量检查流程能够早于解决此问题并将其送达用户。 […]

在Swift中选择正确的失败方法

Swift的一个主要重点是编译时安全性-使我们(作为开发人员)可以轻松地专注于编写可预测性更高,更不易出现运行时错误的代码。 但是,有时事情确实由于各种原因而失败-因此,本周,让我们看一下如何适当地处理此类失败,以及我们可以使用哪些工具来做到这一点。 几周前,我们在“在Swift中处理非可选的可选内容”中介绍了如何处理不是真正可选的可选内容 。 在那篇文章中,我介绍了将preconditionFailure()与guard结合使用的情况,而不是强制展开,并介绍了微框架Require,它提供了方便的API。 从那篇文章开始,许多人问到preconditionFailure()和assert()之间有什么区别,以及它与Swift的throwing功能之间的关系。 因此,在这篇文章中,让我们仔细研究一下所有这些语言功能以及何时使用它们。 让我们从清单开始 据我所知,这是所有可以处理Swift中错误的方法: 返回 nil 或错误枚举值。 错误处理的最简单形式是从遇到错误的函数中简单地返回nil (如果使用Result枚举作为返回类型,则返回.error情况)。 尽管这在许多情况下确实很有用,但将其过度用于所有错误处理会迅速导致使用API​​麻烦,并且还存在隐藏错误逻辑的风险。 引发错误 (使用throw MyError ),这要求调用者使用do, try, catch模式处理潜在的错误。 另外,可以使用try?忽略错误try? 在呼叫站点。 使用 assert() 和 assertionFailure()来验证某个条件为真。 默认情况下,这会在调试版本中导致致命错误,而在发行版本中会被忽略。 因此, 不能保证触发断言后执行就会停止,因此有点像严重的运行时警告。 使用 precondition() 和 preconditionFailure()代替断言。 关键区别在于,即使在发行版中,也总是*对它们进行评估。 这意味着您可以保证,如果不满足条件,执行将永远不会继续。 调用 fatalError() -在子类化符合NSCoding系统类(例如UIViewController fatalError() ,您可能已经在Xcode生成的init(coder:)实现中看到了此NSCoding 。 直接调用它会杀死您的进程。 调用 exit() ,使用代码将其存在于您的进程中。 当您可能想退出全局范围时(例如在main.swift ),这在命令行工具和脚本中非常有用。 *除非您使用 Ounchecked 优化模式 进行编译 。 可恢复与不可恢复 选择正确的失败方法时,要考虑的关键是确定所发生的错误是否可恢复 […]

只是我的类型! — Swift中的自定义类型和错误处理

在坐下来编写代码之前,重要的是解决您需要处理的第一个错误,而不是try -ing。 阅读文档或花时间学习错误处理并不是大多数人都觉得有趣的时光。 起初绝对不是我的。 但是,在探索了有关该主题的一些教程和当代文献之后,我发现在构造自定义类型以处理错误方面有一定的赞赏。 无论您是终身使用的Swift开发人员,还是刚入门的人,都有可能听说过Functional Programming 。 函数式Swift是一个很棒的资源,它是Swift中函数式编程的简介。 尽管此资源着重介绍了许多很棒的主题,但我发现有关枚举和Swift错误的部分在我的项目中特别有用。 这篇文章将带您浏览一些受这些部分启发的示例。 以下示例可在我的演示存储库中的操场上找到。 随意克隆或下载仓库,然后继续! 我确定我们已经编写了所有方法来检查数组或字典中的某些值。 这些容器类型是Swift标准库的一部分,是iOS开发不可或缺的一部分。 在下面的示例中,我们将优化一种方法,该方法仅使用个人的memberName来检索团队成员的数量。 但是,要获取团队成员的数量,需要先查找团队。 构建此方法的合理方法可能如下所示: 使用可选的返回类型 func numberOfTeamMembers(memberName:String)->整数? {卫队让team = teamNames [memberName]否则{return nil} 后卫让号= teamMembers [team] else {return nil} 返回号码 } 然后,我们可以像下面这样在我们的代码中调用此方法: let someLookup = numberOfTeamMembers(memberName: “Tommy”) 还不错吧? 我们的numberOfTeamMembers(memberName:)方法将返回可选的Int? 如果查找成功。 否则,如果其中一项检查失败, someLookup将包含nil 。 尽管这似乎是解决问题的一种合理方法,但我们对查找失败的原因一无所知。 换句话说,如果上述方法返回nil ,那么我们将不知道哪些检查没有通过。 对于更复杂的方法,在跟踪查找错误的来源时可能会出现问题。 numberOfTeamMembers(memberName:)方法的缺点之一在于其返回类型Int? 。 如果我们可以创建自己的返回类型怎么办? 具体来说,如果查找成功,则可以返回Int的类型,如果查找失败,则可以返回详细的错误。 为此,我们可以尝试如下操作: […]

合理,类型安全且灵活的实现,用于管理Swift App中的错误

上周,我开始重构一些与我现在正在使用的应用程序内的错误管理有关的代码。 我试图在互联网上找到一些实现示例,但是没有运气。 这就是为什么我在这里介绍自己的原因。 错误架构 在大多数情况下,应用程序仅用作前端,以向用户呈现信息。 因此,它与为它提供所需服务和数据的不同实体进行交互。 该实体是例如在线API,本地数据库或第三方框架。 他们所有人都会遇到错误。 我们应用程序的目标是捕获它们并做出相应反应,并在必要时通知用户。 为此,通常将错误与唯一的域ID(通常是字符串)和该域内的唯一代码(通常是整数)相关联,以识别错误。 因此错误架构如下所示: 在大多数情况下,错误还将包含其他关联数据,例如,如果发生错误,您将需要向用户显示本地化描述。 那么,您如何将所有这些信息反映到实现中? 更重要的是,如何使实施易于使用,组织合理,灵活且类型安全? 此外,最好在每个错误域内保修唯一的错误代码,并在编译时在我们的应用程序内保修唯一的域ID 。 一,错误的最低要求 我们可以使用协议指定它们: 我们还可以扩展该协议并添加一些有用的东西: 因为我们将使用具有原始整数值的枚举,所以我们添加了初始化程序和code属性的默认实现。 我们还添加了domain属性,因此我们可以访问错误的域ID,而无需访问其封闭类型(我们在协议中将其声明为静态)。 二,用于存储错误信息的类型 枚举类型是为此目的。 它还允许将原始值链接到每种情况,并保证此原始值是唯一的。 它们是存储错误代码的理想选择。 与ErrorProtocol一起,我们实现了一个基本错误,该错误在编译时为每个域强制使用唯一的错误代码。 域ID不能保证是唯一的(我没有在Swift语言中找到在编译时强制执行的工具)。 三,组织代码 为了组织代码,我选择镜像错误体系结构。 使用嵌套类型,我创建了一个伞形类型,用于存储所有不同的错误枚举(每个枚举与一个错误域匹配): 四,伞型的要求 给定一个域和一个代码,每种包装对应于多个错误域的枚举的伞型都应该能够返回错误。 我们可以通过使伞形类型符合以下协议来获得此功能: 在这种情况下,匹配函数负责探索伞型下每个枚举的域ID,并返回与域和代码匹配的错误。 由于Swift是一种类型安全的语言,因此我们需要为所有包含的枚举指定通用类型。 我们可以通过使用非通用协议作为具体类型来实现。 所有封闭的枚举都应符合此协议以及ErrorProtocol。 真实的例子 让我们看一个真实的例子。 现在,我正在一个名为AVO的应用程序中使用此实现(因此,如果您在即将发布的代码中看到AVO,现在您知道原因了)。 首先,我创建了一个满足我的需求的错误协议,该协议继承自ErrorProtocol并包含错误的本地化描述: 其次,我创建了一个伞形类型来存储所有错误枚举。 我使它符合ErrorUmbrellaProtocol并实现匹配功能: 然后添加错误枚举(在这种情况下为两个域,即内部应用程序错误和服务器错误): 现在我们可以如下使用所有这些。 例如,假设我们从服务器获取域ID和错误代码: 为了检查我们收到的确切错误,(如果您要做的不只是显示本地化的错误说明,还可以通过几种方法来做到这一点: 而且将错误信息发送到应用之外也非常容易: 干净吗? ^^

使用Sentry自动化错误处理的快速入门

Sentry是一个用于跟踪应用程序错误的出色工具,在本简短指南中,我将向您展示如何将其添加到iOS应用程序中。 注册新账号。 您是一名开发人员,我希望我不需要逐步介绍。 2.如果没有设置CocoaPods,请安装它并在项目目录中运行pod init,它将引导您完成创建Podfile的操作 11.将绝对路径复制到脚本中,并将其粘贴到编辑器框中 12.你做完了✅! 您现在可以自动跟踪错误。 🥳

斯威夫特剧院

程序执行者容易受到儿子执行死刑的侵害。 除此以外,重要的反叛者也是重要人物。 Créerun type d’erreur d erreur类型的“默认”错误版本“ VersionParseError”使我符合协议“ Error”。 在peen rencontrer上获得Cerest ce loc quiper permettre de Capturer etgérertous les type d’erreurs que l’on 丹斯·勒· 杜 (Dans le do )在appret notre 投掷功能 àl’aide dumot -clétry上, 丹斯·查克追上了法雷特d’erreur que l’on veutgérer 。 在运行时,根据捕获的错误和执行情况,也可以根据执行人员的指示进行操作。 恩芬(Enfin),勒德尼耶(le dernier)在n’aurait paspenséepeuvent上捕捉到了无害的法律和义务的汽车。 在所有人面前,alors tous les抓住了serontignorés。 所有版本的les erreurs dans chaque catch均标榜为une版本和简洁版本。 公平的公平对待: ligne 6,在错误的通讯录中,您将在rencontrée的所有语言中找到正确的答案。 Quelques […]