swift学习笔记(16)- 错误处理

16、Swift 协议、协议扩展与错误处理详解 本文详细解析了 Swift 中的协议、协议扩展与错误处理机制。内容涵盖协议的应用、Swift 2.0 之前的错误处理方式、Swift 2 及之后版本的错误处理模型、do-catch 块的使用、try? 和 try! 的区别、defer 语句的作用,以及如何结合协议实现灵活的错误处理策略。同时介绍了可用性属性在多版本系统兼容中的应用,并通过示例代码帮助开发者更好地理解和运用这些特性。文章旨在提升代码的安全性和可维护性,适用于不同层次的 Swift 开发者。 阅读详情

表示并抛出错误

在 Swift 中,错误用符合Error协议的类型的值来表示。这个空协议表明该类型可以用于错误处理。

Swift 的枚举类型尤为适合构建一组相关的错误状态,枚举的关联值还可以提供错误状态的额外信息。例如,你可以这样表示在一个游戏中操作自动贩卖机时可能会出现的错误状态:

enum VendingMachineError: Error {
    case invalidSelection                    //选择无效
    case insufficientFunds(coinsNeeded: Int) //金额不足
    case outOfStock                          //缺货
}

抛出一个错误可以让你表明有意外情况发生,导致正常的执行流程无法继续执行。抛出错误使用throw关键字。例如,下面的代码抛出一个错误,提示贩卖机还需要5个硬币:

throw VendingMachineError. insufficientFunds(coinsNeeded: 5)

处理错误

某个错误被抛出时,附近的某部分代码必须负责处理这个错误,例如纠正这个问题、尝试另外一种方式、或是向用户报告错误。

Swift 中有4种处理错误的方式。你可以把函数抛出的错误传递给调用此函数的代码、用do-catch语句处理错误、将错误作为可选类型处理、或者断言此错误根本不会发生。

当一个函数抛出一个错误时,你的程序流程会发生改变,所以重要的是你能迅速识别代码中会抛出错误的地方。为了标识出这些地方,在调用一个能抛出错误的函数、方法或者构造器之前,加上try关键字,或者try?或try!这种变体。

注意
Swift 中的错误处理和其他语言中用try,catch和throw进行异常处理很像。和其他语言中(包括 Objective-C )的异常处理不同的是,Swift 中的错误处理并不涉及解除调用栈,这是一个计算代价高昂的过程。就此而言,throw语句的性能特性是可以和return语句相媲美的。

用 throwing 函数传递错误

为了表示一个函数、方法或构造器可以抛出错误,在函数声明的参数列表之后加上throws关键字。一个标有throws关键字的函数被称作throwing 函数。如果这个函数指明了返回值类型,throws关键词需要写在箭头(->)的前面。

func canThrowErrors() throws -> String
func cannotThrowErrors() -> String

一个 throwing 函数可以在其内部抛出错误,并将错误传递到函数被调用时的作用域。

注意
只有 throwing 函数可以传递错误。任何在某个非 throwing 函数内部抛出的错误只能在函数内部处理。

下面的例子中,VendingMachine类有一个vend(itemNamed:)方法,如果请求的物品不存在、缺货或者投入金额小于物品价格,该方法就会抛出一个相应的VendingMachineError:

struct Item {
    var price: Int
    var count: Int
}

class VendingMachine {
    var inventory = [
        "Candy Bar": Item(price: 12, count: 7),
        "Chips": Item(price: 10, count: 4),
        "Pretzels": Item(price: 7, count: 11)
    ]
    var coinsDeposited = 0
    func dispenseSnack(snack: String) {
        print("Dispensing \(snack)")
    }

    func vend(itemNamed name: String) throws {
        guard let item = inventory[name] else {
            throw VendingMachineError.InvalidSelection
        }

        guard item.count > 0 else {
            throw VendingMachineError.OutOfStock
        }

        guard item.price <= coinsDeposited else {
            throw VendingMachineError.InsufficientFunds(coinsNeeded: item.price - coinsDeposited)
        }

        coinsDeposited -= item.price

        var newItem = item
        newItem.count -= 1
        inventory[name] = newItem

        print("Dispensing \(name)")
    }
}

在vend(itemNamed:)方法的实现中使用了guard语句来提前退出方法,确保在购买某个物品所需的条件中,有任一条件不满足时,能提前退出方法并抛出相应的错误。由于throw语句会立即退出方法,所以物品只有在所有条件都满足时才会被售出。

因为vend(itemNamed:)方法会传递出它抛出的任何错误,在你的代码中调用此方法的地方,必须要么直接处理这些错误——使用do-catch语句,try?或try!;要么继续将这些错误传递下去。例如下面例子中,buyFavoriteSnack(_:vendingMachine:)同样是一个 throwing 函数,任何由vend(itemNamed:)方法抛出的错误会一直被传递到buyFavoriteSnack(person:vendingMachine:)函数被调用的地方。

let favoriteSnacks = [
    "Alice": "Chips",
    "Bob": "Licorice",
    "Eve": "Pretzels",
]
func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
    let snackName = favoriteSnacks[person] ?? "Candy Bar"
    try vendingMachine.vend(itemNamed: snackName)
}

上例中,buyFavoriteSnack(person:vendingMachine:)函数会查找某人最喜欢的零食,并通过调用vend(itemNamed:)方法来尝试为他们购买。因为vend(itemNamed:)方法能抛出错误,所以在调用的它时候在它前面加了try关键字。

throwing构造器能像throwing函数一样传递错误.例如下面代码中的PurchasedSnack构造器在构造过程中调用了throwing函数,并且通过传递到它的调用者来处理这些错误。

struct PurchasedSnack {
    let name: String
    init(name: String, vendingMachine: VendingMachine) throws {
        try vendingMachine.vend(itemNamed: name)
        self.name = name
    }
}

用 Do-Catch 处理错误

可以使用一个do-catch语句运行一段闭包代码来处理错误。如果在do子句中的代码抛出了一个错误,这个错误会与catch子句做匹配,从而决定哪条子句能处理它。

catch子句不必将do子句中的代码所抛出的每一个可能的错误都作处理。如果所有catch子句都未处理错误,错误就会传递到周围的作用域。然而,错误还是必须要被某个周围的作用域处理的——要么是一个外围的do-catch错误处理语句,要么是一个 throwing 函数的内部。

var vendingMachine = VendingMachine()
vendingMachine.coinsDeposited = 8
do {
    try buyFavoriteSnack("Alice", vendingMachine: vendingMachine)
} catch VendingMachineError.InvalidSelection {
    print("Invalid Selection.")
} catch VendingMachineError.OutOfStock {
    print("Out of Stock.")
} catch VendingMachineError.InsufficientFunds(let coinsNeeded) {
    print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
}
// 打印 “Insufficient funds. Please insert an additional 2 coins.”

将错误转换成可选值

可以使用try?通过将错误转换成一个可选值来处理错误。如果在评估try?表达式时一个错误被抛出,那么表达式的值就是nil。例如,在下面的代码中,x和y有着相同的数值和等价的含义:

func someThrowingFunction() throws -> Int {
    // ...
}

let x = try? someThrowingFunction()

let y: Int?
do {
    y = try someThrowingFunction()
} catch {
    y = nil
}

如果someThrowingFunction()抛出一个错误,x和y的值是nil。否则x和y的值就是该函数的返回值。注意,无论someThrowingFunction()的返回值类型是什么类型,x和y都是这个类型的可选类型。例子中此函数返回一个整型,所以x和y是可选整型。

如果你想对所有的错误都采用同样的方式来处理,用try?就可以让你写出简洁的错误处理代码。例如,下面的代码用几种方式来获取数据,如果所有方式都失败了则返回nil:

func fetchData() -> Data? {
    if let data = try? fetchDataFromDisk() { return data }
    if let data = try? fetchDataFromServer() { return data }
    return nil
}

禁用错误传递

有时你知道某个throwing函数实际上在运行时是不会抛出错误的,在这种情况下,你可以在表达式前面写try!来禁用错误传递,这会把调用包装在一个不会有错误抛出的运行时断言中。如果真的抛出了错误,你会得到一个运行时错误。

例如,下面的代码使用了loadImage(atPath:)函数,该函数从给定的路径加载图片资源,如果图片无法载入则抛出一个错误。在这种情况下,因为图片是和应用绑定的,运行时不会有错误抛出,所以适合禁用错误传递:

let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")

指定清理操作

可以使用defer语句在即将离开当前代码块时执行一系列语句。该语句让你能执行一些必要的清理工作,不管是以何种方式离开当前代码块的——无论是由于抛出错误而离开,还是由于诸如return或者break的语句。例如,你可以用defer语句来确保文件描述符得以关闭,以及手动分配的内存得以释放。

defer语句将代码的执行延迟到当前的作用域退出之前。该语句由defer关键字和要被延迟执行的语句组成。延迟执行的语句不能包含任何控制转移语句,例如break或是return语句,或是抛出一个错误。延迟执行的操作会按照它们被指定时的顺序的相反顺序执行——也就是说,第一条defer语句中的代码会在第二条defer语句中的代码被执行之后才执行,以此类推。

func processFile(filename: String) throws {
    if exists(filename) {
        let file = open(filename)
        defer {
            close(file)
        }
        while let line = try file.readline() {
            // 处理文件。
        }
        // close(file) 会在这里被调用,即作用域的最后。
    }
}

上面的代码使用一条defer语句来确保open(:)函数有一个相应的对close(:)函数的调用。

11、Swift 5 错误处理与 iOS 16 应用开发架构详解 本博客详细解析了 Swift 5 的错误处理机制,涵盖错误捕获、`defer` 语句等核心技术,并深入探讨了 iOS 16 应用开发的架构设计,包括 MVC 模式、目标-动作模式、子类化和委托等关键概念。同时,通过构建一个交互式的华氏温度转摄氏温度的 iOS 应用,手把手引导开发者完成从项目创建、界面设计到功能实现的完整开发流程,适合 iOS 开发新手入门与实践。 阅读详情

相关推荐

72、在 iOS 16 上使用 Swift 处理目录和文件

本文详细介绍了在 iOS 16 中使用 Swift 进行文件和目录操作的方法。涵盖了 FileManager、FileHandle 和 Data 类的使用,包括文档目录、临时目录的获取,目录的创建与删除,文件的读写、复制、移动、权限检查等常见操作,并提供了流程图、代码示例及性能优化建议,帮助开发者高效处理 iOS 平台的文件系统任务。

cicd6pipeline的博客 68

Swift 4.0 中的错误处理及抛出错误

在Swift的标准库,很多方法名后都带有’throws’这个关键词, ‘throws’表示该方法在执行过程中遇到错误则抛出,但不会crash。 下面是Swift标准库中的一个构造方法,String、Data都有该构造方法 public init(contentsOf url: URL) throws 当我们通过该方法去构造一个实例时怎么去捕获抛出的错误呢(如果有错误)? 捕获错误 在S...

我只是一个攻城狮 750

Swift错误处理与API可用性检测

本文主要探讨了在Swift中如何处理错误、确保代码块在方法退出前执行以及检查API的可用性。通过实际代码案例,展示了throw、do、try、catch语法的使用,以及defer和#available语法的实现,帮助开发者更好地管理应用中的异常情况和环境兼容性。

weixin_42513209的博客 355

golang学习-panic

转载自 https://www.cnblogs.com/liuzhongchao/p/10112739.html package main import "fmt" func main() { //Go语言追求简洁优雅,所以,Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为, //将异常与控制结构混在一起会很容易使得代码变得混乱。因为开发者很容易滥用异常,甚至一个小小的错误都抛出一个异常。 //在Go语言中,使用多值返回来返回错误。不要用异常代替错误,

lilele12211104的专栏 337

throwing-function:启用检查的异常的Java 8+功能接口+适配器

启用了检查异常的Java 8+功能接口 和适配器 基本原理 由于没有throws ...子句,因此标准的java.util.function Function Interfaces不被检查为异常友好的,这导致通过添加try-catch样板来处理它们的繁琐而冗长的必要性。 这使得单线是这样的: path -> new URI(path) 变得冗长: path -> { try { return new URI(path); } catch (URISyntaxException e) { throw new RuntimeException(e); } } 通过应用com.pivovarit.function功能接口,可以重新获得清晰性和可读性: ThrowingFunction<String, URI, URISyntaxEx

throwing-function, 已经检查的异常使用Java 8 功能接口 适配器.zip

throwing-function, 已经检查的异常使用Java 8 功能接口 适配器 函数已经检查的异常使用了 Java 8 功能接口 适配器 提供了用于解决 Java 8检查的异常的快捷方式。你可以定义抛出checked异常的函数:ThrowingFunction<String, URI,

Throwing-function: Java 8+ 中的异常处理优化

Throwing-function: Java 8+ 中的异常处理优化 Throwing-function 是一个开源项目,旨在为 Java 8 及以上版本提供支持检查异常的函数式接口。该项目主要使用 Java 语言开发。 核心功能 该项目引入了一系列新的函数式接口,这些接口允许在 lambda 表达式中抛出检查异常。Java 标准库中的 java.util.function 接口并不支持抛出检查...

gitblog_01004的博客 438

大样本EEG公共数据集汇总

描述: OpenNeuro平台包含多个认知障碍相关的EEG数据集,例如针对轻度认知障碍(MCI)或阿尔茨海默病(AD)的研究。描述: 天普大学医院EEG语料库包含大量临床EEG记录,可通过元数据筛选出与认知障碍相关的片段(如诊断标签包含dementia或MCI)。描述: ADNI主要提供多模态神经影像数据(MRI/PET),但部分合作研究整合了EEG数据。样本量: 部分数据集包含100+被试(例如结合MRI与EEG的多模态数据)。样本量:30,000+ EEG记录(持续更新,全球最大临床EEG数据库)。

谁人打的太极拳的博客 1758

Swift 中异常抛出和四种异常处理

在Swift中你可以像其他语言一样抛出异常处理异常,今天我们就详细地说说Swift中的异常抛出和处理。 在一开始我们要定义错误或者说是异常,Swift中的一些简单异常可以使用枚举定义,注意这个枚举要继承一个空协议Error,如下代码:enum OperationError : Error { case ErrorOne case ErrorTwo case ErrorThr

一步一迹的博客 1万+

学习海康VisionMaster之BLOB分析

6):软阈值(相对):是一种动态阈值分割方法,其核心思想是 基于图像局部特性(如背景或参考区域)自适应调整阈值范围,适用于光照变化明显、背景灰度不均的场景。3:拖入位置修正功能:这个非常重要,模版匹配成功后会得到新的匹配坐标,那和创建模版时候的原点坐标会组合成一个坐标变换矩阵,通过这个矩阵,那后续的blob分析窗口则可以实现精确定位来查找目标对象。(2):设定参数:这里阈值方式是blob的核心算法,根据不同的应用场景来选择不同的阈值方式。8:高级参数:是设定blob区域的特征范围,用于筛选出来特定的区域。

yuhouxiyang的专栏 3615

网络基础(二):数制转换与分类编址的IPv4地址

本文介绍数制转换、IP地址、分类编址的IPv4地址,希望对你有帮助!

十七拾的博客 1052

16-Swift错误处理

 错误处理是响应错误以及从错误中恢复的过程。swift提供了在运行对可恢复错误抛出、捕获、传送和操作的高级支持(错误处理又称之为异常处理)。  某些操作并不能总是保证执行所有代码都可以执行或总会产生出有用的结果。可选类型用来表示值可能为空,但当执行失败的时候,通常要去了解此次失败是由什么引起的,代码就可以做出与之对应的反应。  例如,对磁盘上的某个文件的读取操作,该任务会有多种可能失败的情形,包括...

快把钟哥带走 198

AI赋能运筹优化:从参数生成到智能求解的工程实践

运筹学通过线性规划、整数规划等数学模型,为供应链、物流、生产排程等复杂决策问题寻找最优解,其核心价值在于提升资源利用效率与决策科学性。传统方法依赖精确的输入参数与专家经验,面临数据不准、建模门槛高、求解调优难等挑战。人工智能技术的引入,正从原理层面重塑这一流程:通过深度学习模型生成更贴合现实的动态参数(如需求分布、行驶时间),利用自然语言处理降低建模门槛,并借助强化学习对求解器进行智能参数调优。这种AI与运筹学的融合,在工程实践中显著提升了优化系统的自适应能力与求解效率,使其在应对实时交通、柔性生产调度等动

weixin_26913055的博客 595

Swift 5.1 (16) - 错误处理

Swift 5.1 (16) - 错误处理错误的表示和抛出 在Swift中,错误由符合Error协议的类型的值表示。Error是空协议,表示类型可用于错误处理。 错误的处理 Swift中的错误处理类似于其他语言中的异常处理,使用了try,catch和throw关键字。但是与许多其他语言(包括Objective-C)不一样的是,Swift中的错误处理不涉及展示函数调用的堆栈信息。因此throw与return语句的性能相当。 使用抛出函数来传播错误 抛出函数:函数声明中标记有throws关键.

box_kun的博客 434

基于大疆TSDK与Pix4D的热红外数据工程化处理:从RJPG到温度正射影像的完整工作流

本文详细介绍了基于大疆TSDK与Pix4D的热红外数据工程化处理完整工作流。通过Python脚本自动化解析RJPG格式的热红外图像,提取并转换其中的原始辐射数据为包含真实温度信息的TIFF文件,再结合Pix4Dmapper进行批量拼接,最终生成可直接用于GIS分析的温度正射影像图。该流程解决了手动处理效率低下、参数校准复杂等难题,实现了从原始数据到定量分析成果的高效、准确、可重复生产。

weixin_29161785的博客 374

STM32F4_DHT11数字温湿度传感器

开机的时候先检测是否有DHT11存在,如果没有,则提示错误。DHT11和DS18B20相同,传感器输出的都是未编码的二进制数字。本节我们将利用STM32F4来读取DHT11的温湿度传感器,获取环境的温度和湿度值。因此:温湿度的读取方式就是整数部分的二进制转换成十进制放在整数部分;小数部分的二进制转换成十进制放在小数部分。DHT11和MCU的一次通讯时间最大3ms,主机连续向DHT11采样的间隔建议不小于100ms。DHT11是广州奥松有限公司生产的一款温湿度一体化的数字传感器。数据分小数部分和整数部分。

light_2025的博客 3431

16、Swift 编程:协议、扩展与错误处理全解析

本博客深入解析了 Swift 编程语言中的协议、协议扩展、错误处理机制、defer 语句以及可用性属性的使用。通过实际代码示例,展示了如何利用协议和扩展实现灵活的代码复用,如何在不同 Swift 版本中处理错误,以及如何使用 defer 和可用性检查确保代码的健壮性和兼容性。此外,还介绍了错误处理的最佳实践,帮助开发者编写更安全、更高效的 Swift 应用。

gin88的博客 83

机器学习扩散模型简介

​ 扩散模型是生成模型,在过去几年中越来越受欢迎,这是有充分理由的。仅在 2020 年代发布的几篇开创性论文就向世界展示了 Diffusion 模型的能力,例如在图像合成方面击败 GAN[6]。最近,从业者将看到DALL-E 2(OpenAI 上个月发布的图像生成模型)中使用的扩散模型。

gongdiwudu的专栏 4258

新鲜上下文攻击协议:old-coder如何用独立验证Agent防范AI自我欺骗

old-coder 是一个面向 coding agent 的证据驱动开发 skill,它让 AI 代码先闯过 SPEC → 关卡(gauntlet)→ EVIDENCE 的层层自证,再通过"新鲜上下文攻击协议"引入独立验证 Agent 防范 AI 自我欺骗:验证者只能拿到 4 项输入、先盲攻后比对,结论由人类评分。本文拆解这套协议的完整规则,以及它对 100% 覆盖率限流器发起 6 轮真实攻击的记

gitblog_00929的博客 734

Python 爬虫实战:全球渔业船舶捕捞记录数据采集与分析全攻略

通过本项目,我们实现了对全球渔业船舶捕捞记录数据的采集、处理和可视化,为渔业资源管理和海洋生态保护提供了数据支持。未来,可以进一步结合机器学习和深度学习技术,对捕捞行为进行预测和分类,提高对非法捕捞活动的识别能力。

2201_76125261的博客 555

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

IOS开发Swift笔记16-错误处理

错误类型 开发过程中常见的错误类型 语法错误(编译报错) 逻辑错误 运行时错误(可能导致闪崩,一般也叫异常) … —————————————————— 自定义错误 Swift中可以通过Error协议自定义运行时的错误信息 函数内部通过throw抛出自定义Error,可能会抛出Error的函数必须加上throws enum SomeError: Error { case illegalArg(String) case outOfBounds(Int, Int) case outOf

qq_25218777的博客 305

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

swift 颜色 16进制_扔进Swift的封盖

swift 颜色 16进制Difficulty: Beginner | Easy | Normal | ChallengingThis article has been developed using Xcode 11.4.1, and Swift 5.2.2 难度:初学者| 容易 | 普通| 具有挑战性本文是使用Xcode 11.4.1和Swift 5.2.2开发的 This article ...

weixin_26638123的博客 368

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Xcode 16 中 Swift Testing 的参数化(Parameterized)机制趣谈

在本篇博文中,我们继续介绍了 Xcode 16 全新 Swift Testing 中的参数化(Parameterized)测试机制。有此神兵利器,相信小伙伴们在今后的单元测试中必将出奇制胜、手到擒来!

享受开发,颠倒银河 1424

swift string转int_Swift学习笔记

欢迎点击上方蓝字“iOS进阶宝典”关注我们再点击右上角“...”菜单,选择“设为星标”作者 |iOS_天气来源 | 简书学习swift的笔记Objective-C是很好的语言,Runtime机制、消息机制等也是爱不释手。Swift一直在更新,闲暇时间学一遍。学习的Blog:《从零开始学swift》以下代码全部在playground进行的尝试变量let 是常量 var 是变量 不能修改的...

weixin_39999222的博客 561

Swift语法学习笔记

[D.2]对Swift语法整理的非常好,这里主要基于这个文档提取出Swift相对于C/C++,Objective-C而言相对突出的语法。 不需要(加上也没错)在语句结尾加分号了(这个习惯可能改起来比较麻烦);与此同时,两个语句最好要写两行了~,非要写在一行的话,就要添加分号来分割了。 原生类型(值类型) Bool Int Int8 Int16 UInt UInt8 ...

刘国元的专栏 277

Swift开发者必看:用speech-swift集成DeepFilterNet3-CoreML的完整代码示例

DeepFilterNet3-CoreML是一个基于CoreML框架的音频降噪模型,专为iOS和macOS平台优化。它能够有效去除音频中的背景噪音,提升语音清晰度,非常适合集成到语音通话、录音应用等场景中。作为Swift开发者,通过speech-swift框架可以轻松实现这一强大功能。 ## 准备工作 ### 1. 克隆项目仓库 首先,需要将项目代码克隆到本地: ```bash git c

gitblog_00549的博客 941
上一篇: swift学习笔记(15)- 可选链
下一篇: iOS appIcon生成和设置
winterLiao
博客等级 码龄10年 5粉丝 23原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值