IOS Swift 从入门到精通: 可选项、展开和类型转换

2024-06-22 20:52

本文主要是介绍IOS Swift 从入门到精通: 可选项、展开和类型转换,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 处理缺失数据
  • 展开可选值
  • 用保护装置解开
  • 强制展开
  • 隐式解包可选值
  • 零合并
  • 可选链式调用
  • 可选尝试
  • 可失败的初始化器
  • 类型转换
  • 总结

处理缺失数据

我们已经使用诸如 之类的类型Int来保存像 5 这样的值。但是如果您想存储age用户的属性,如果您不知道某人的年龄,您会怎么做?

您可能会说“好吧,我会存储 0”,但这样一来,您就会混淆新生婴儿和您不知道年龄的人。您可以使用特殊数字(例如 1000 或 -1)来表示“未知”,这两个年龄都是不可能的,但您真的会记住所有使用这个数字的地方吗?

Swift 的解决方案称为可选类型,你可以用任意类型创建可选类型。可选整数可能包含数字 0 或 40,但它可能根本没有值 - 它可能真的缺失了,这是nilSwift 中的情况。

要使类型可选,请在其后添加问号。例如,我们可以像这样创建一个可选整数:

var age: Int? = nil

这并不代表任何数字——它什么也不代表。但如果我们后来知道了年龄,我们可以使用它:

age = 38

展开可选值

可选字符串可能包含像“Hello”这样的字符串,或者可能为零——什么都没有。

考虑这个可选字符串:

var name: String? = nil

如果我们使用会发生什么name.count?真正的字符串具有count存储其有多少个字母的属性,但这是nil– 它是空内存,而不是字符串,因此它没有count。

因此,尝试读取name.count是不安全的,Swift 不允许这样做。相反,我们必须查看可选值的内部并查看其中的内容 - 这个过程称为解包。

解包可选值的一种常见方法是使用if let语法,该语法使用条件进行解包。如果可选值中有一个值,那么您可以使用它,但如果没有,则条件不成立。

例如:

if let unwrapped = name {print("\(unwrapped.count) letters")
} else {print("Missing name.")
}

如果name包含字符串,它将被放入unwrapped常规中String,我们可以count在条件中读取其属性。或者,如果name为空,else则将运行代码。

用保护装置解开

的另一种方法if let是guard let,它也可以解开可选项。guard let将为您解开可选项,但如果它nil在里面找到它,它会期望您退出使用它的函数、循环或条件。

if let但是,和之间的主要区别guard let在于,解包的可选项在代码之后仍然可用guard。

让我们用一个函数来尝试一下greet()。它将接受一个可选字符串作为其唯一参数并尝试解包它,但如果里面没有任何内容,它将打印一条消息并退出。因为使用解包的可选值在完成guard let后仍然存在guard,所以我们可以在函数末尾打印解包的字符串:

func greet(_ name: String?) {guard let unwrapped = name else {print("You didn't provide a name!")return}print("Hello, \(unwrapped)!")
}

使用guard let可以让你在函数开始时处理问题,然后立即退出。这意味着函数的其余部分是快乐路径 - 如果一切正确,你的代码将采用该路径。

强制展开

可选值表示可能存在也可能不存在的数据,但有时您肯定知道某个值不为 nil。在这些情况下,Swift 允许您强制解包可选值:将其从可选类型转换为非可选类型。

例如,如果您有一个包含数字的字符串,则可以将其转换为Int如下形式:

let str = "5"
let num = Int(str)

这是num一个可选项 Int,因为您可能尝试转换像“Fish”而不是“5”这样的字符串。

尽管 Swift 不确定转换是否有效,但您可以看到代码是安全的,因此您可以通过!在之后写入来强制解开结果Int(str),如下所示:

let num = Int(str)!

Swift 会立即解开可选值并将其转换为num常规值Int,而不是Int?。但如果你错了——ifstr是无法转换为整数的东西——你的代码就会崩溃。

因此,只有当您确定它是安全的时候才应该强制解包 - 这就是它通常被称为崩溃操作员的原因。

隐式解包可选值

与常规可选项一样,隐式解包的可选项可能包含一个值,也可能是nil。但是,与常规可选项不同,您无需解包即可使用它们:您可以像使用它们根本不是可选项一样使用它们。

隐式解包的可选类型是通过在类型名称后添加感叹号来创建的,如下所示:

let age: Int! = nil

因为它们的行为就像已经解包一样,所以您不需要if let或guard let使用隐式解包的可选值。但是,如果您尝试使用它们并且它们没有值(如果有的话nil),您的代码就会崩溃。

隐式解包可选值之所以存在,是因为有时变量一开始为 nil,但在需要使用之前始终会有一个值。因为你知道在需要它们时它们会有一个值,所以不必一直写这个值会很有帮助if let。

话虽如此,如果您可以使用常规可选项,这通常是个好主意。

零合并

零合并运算符解包可选项并返回其中的值(如果有)。如果没有值(如果可选项有值nil),则使用默认值。无论哪种方式,结果都不是可选项:它要么是可选项内部的值,要么是用作备份的默认值。

这是一个接受整数作为其唯一参数并返回可选字符串的函数:

func username(for id: Int) -> String? {if id == 1 {return "Taylor Swift"} else {return nil}
}

如果我们使用 ID 15 调用该函数,我们会返回,nil因为无法识别该用户,但是使用 nil 合并,我们可以提供一个默认值"Anonymous",如下所示:

let user = username(for: 15) ?? "Anonymous"

这将检查从函数返回的结果username():如果它是一个字符串,那么它将被解开并放入user,但如果它有nil内部,那么将使用"Anonymous"

可选链式调用

Swift 为我们提供了使用可选变量的快捷方式:如果你想访问类似a.b.c和b可选的内容,你可以在它后面写一个问号以启用可选链接:a.b?.c。

当运行该代码时,Swift 将检查是否b有值,如果有,则nil该行的其余部分将被忽略 - Swift 将nil立即返回。但是如果它有值,它将被解包并继续执行。

为了尝试这一点,这里有一个名称数组:

let names = ["John", "Paul", "George", "Ringo"]

我们将使用该数组的属性,如果存在第一个名字或数组为空,first它将返回第一个名字。然后我们可以调用结果使其成为大写字符串:niluppercased()

let beatle = names.first?.uppercased()

那个问号是可选链接——如果first返回nil,那么 Swift 不会尝试将其大写,并且会立即设置beatle为nil。

可选尝试

当我们讨论抛出函数时,我们看了以下代码:

enum PasswordError: Error {case obvious
}func checkPassword(_ password: String) throws -> Bool {if password == "password" {throw PasswordError.obvious}return true
}do {try checkPassword("password")print("That password is good!")
} catch {print("You can't use that password.")
}

运行一个抛出函数,使用do、try和catch来优雅地处理错误。

有两种替代方法try,既然您现在理解了可选项和强制解包,那么这两种方法都会更有意义。

第一个是try?,并将抛出函数更改为返回可选值的函数。如果函数抛出错误,您将被发送nil结果,否则您将获得包装为可选值的返回值。

我们可以像这样try?运行:checkPassword()

if let result = try? checkPassword("password") {print("Result was \(result)")
} else {print("D'oh.")
}

另一种方法是try!,当您确信该函数不会失败时可以使用它。如果该函数确实抛出错误,您的代码将崩溃。

我们try!可以将代码重写如下:

try! checkPassword("sekrit")
print("OK!")

可失败的初始化器

当谈到强制展开时,我使用了以下代码:

let str = "5"
let num = Int(str)

这会将字符串转换为整数,但是因为您可能尝试传递任何字符串,所以您实际得到的是一个可选的整数。

这是一个可失败的初始化器:一个可能成功也可能失败的初始化器。您可以使用init?()而不是将这些初始化器写在您自己的结构和类中init(),如果出现错误则返回nil。返回值将是您类型的可选项,您可以随意解包。

例如,我们可以编写一个Person必须使用九个字母的 ID 字符串创建的结构。如果使用除九个字母字符串以外的任何其他字符串,我们将返回nil,否则我们将照常继续。

Swift 版本如下:

struct Person {var id: Stringinit?(id: String) {if id.count == 9 {self.id = id} else {return nil}}
}

类型转换

Swift 必须始终知道每个变量的类型,但有时你知道的信息比 Swift 知道的多。例如,这里有三个类:

class Animal { }
class Fish: Animal { }class Dog: Animal {func makeNoise() {print("Woof!")}
}

我们可以创建几条鱼和几条狗,并将它们放入一个数组中,如下所示:

let pets = [Fish(), Dog(), Fish(), Dog()]

Swift 可以看到Fish并Dog从类中继承Animal,因此它使用类型推断来创建pets一个数组Animal。

如果我们想要循环遍历pets数组并让所有的狗叫,我们需要执行类型转换:Swift 将检查每只宠物是否是一个Dog对象,如果是,那么我们就可以调用makeNoise()。

这使用了一个名为的新关键字as?,它返回一个可选项:nil如果类型转换失败则为,否则为转换后的类型。

以下是我们在 Swift 中编写循环的方法:

for pet in pets {if let dog = pet as? Dog {dog.makeNoise()}
}

总结

  • 可选项让我们能够以清晰明确的方式表示值的缺失。
  • Swift 不允许我们在未解包的情况下使用可选项,无论是使用if let还是使用guard let。
  • 您可以使用感叹号强制解开可选项,但如果您尝试强制解开,nil您的代码将会崩溃。
  • 隐式解包的可选项没有常规可选项的安全检查。
  • 您可以使用 nil 合并来解开可选项,如果其中没有任何内容,则提供默认值。
  • 可选链接让我们可以编写代码来操作可选项,但如果可选项为空,则代码将被忽略。
  • 您可以使用try?将抛出函数转换为可选的返回值,或者try!在抛出错误时崩溃。
  • 如果您需要您的初始化程序在输入错误输入时失败,请使用init?()可失败的初始化程序。
  • 您可以使用类型转换将一种类型的对象转换为另一种类型的对象。

这篇关于IOS Swift 从入门到精通: 可选项、展开和类型转换的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1085390

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

安卓链接正常显示,ios#符被转义%23导致链接访问404

原因分析: url中含有特殊字符 中文未编码 都有可能导致URL转换失败,所以需要对url编码处理  如下: guard let allowUrl = webUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {return} 后面发现当url中有#号时,会被误伤转义为%23,导致链接无法访问

数论入门整理(updating)

一、gcd lcm 基础中的基础,一般用来处理计算第一步什么的,分数化简之类。 LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; } <pre name="code" class="cpp">LL lcm(LL a, LL b){LL c = gcd(a, b);return a / c * b;} 例题:

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

【IPV6从入门到起飞】5-1 IPV6+Home Assistant(搭建基本环境)

【IPV6从入门到起飞】5-1 IPV6+Home Assistant #搭建基本环境 1 背景2 docker下载 hass3 创建容器4 浏览器访问 hass5 手机APP远程访问hass6 更多玩法 1 背景 既然电脑可以IPV6入站,手机流量可以访问IPV6网络的服务,为什么不在电脑搭建Home Assistant(hass),来控制你的设备呢?@智能家居 @万物互联

poj 2104 and hdu 2665 划分树模板入门题

题意: 给一个数组n(1e5)个数,给一个范围(fr, to, k),求这个范围中第k大的数。 解析: 划分树入门。 bing神的模板。 坑爹的地方是把-l 看成了-1........ 一直re。 代码: poj 2104: #include <iostream>#include <cstdio>#include <cstdlib>#include <al

【C++高阶】C++类型转换全攻略:深入理解并高效应用

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C++ “ 登神长阶 ” 🤡往期回顾🤡:C++ 智能指针 🌹🌹期待您的关注 🌹🌹 ❀C++的类型转换 📒1. C语言中的类型转换📚2. C++强制类型转换⛰️static_cast🌞reinterpret_cast⭐const_cast🍁dynamic_cast 📜3. C++强制类型转换的原因📝

MySQL-CRUD入门1

文章目录 认识配置文件client节点mysql节点mysqld节点 数据的添加(Create)添加一行数据添加多行数据两种添加数据的效率对比 数据的查询(Retrieve)全列查询指定列查询查询中带有表达式关于字面量关于as重命名 临时表引入distinct去重order by 排序关于NULL 认识配置文件 在我们的MySQL服务安装好了之后, 会有一个配置文件, 也就

【iOS】MVC模式

MVC模式 MVC模式MVC模式demo MVC模式 MVC模式全称为model(模型)view(视图)controller(控制器),他分为三个不同的层分别负责不同的职责。 View:该层用于存放视图,该层中我们可以对页面及控件进行布局。Model:模型一般都拥有很好的可复用性,在该层中,我们可以统一管理一些数据。Controlller:该层充当一个CPU的功能,即该应用程序

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显