首页 > 其他分享 >IOS Swift 从入门到精通: 可选项、展开和类型转换

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

时间:2024-06-22 18:59:46浏览次数:20  
标签:类型转换 nil IOS 解包 let 可选项 使用 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: String

    init?(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?()可失败的初始化程序。
  • 您可以使用类型转换将一种类型的对象转换为另一种类型的对象。

标签:类型转换,nil,IOS,解包,let,可选项,使用,Swift
From: https://blog.csdn.net/HE19930303/article/details/139886438

相关文章

  • 类型转换工具类
    1publicstaticpartialclassExtensions2{3#region转换为long4///<summary>5///将object转换为long,若转换失败,则返回0。不抛出异常。6///</summary>7///<paramname="str"></param>8///<r......
  • Kotlin 数据类型详解:数字、字符、布尔值与类型转换指南
    Kotlin数据类型在Kotlin中,变量的类型由其值决定:示例valmyNum=5//IntvalmyDoubleNum=5.99//DoublevalmyLetter='D'//CharvalmyBoolean=true//BooleanvalmyText="Hello"//String然而,从上一章中你了解到,如果需......
  • 华为电脑BIOS设置系统启动顺序
        最近在华为电脑上装了Windows和Ubuntu双系统后,由于安装失误,导致每次开机后都会进入grub界面。    为了正常进入Windows和Ubuntu系统,在开机进入grub界面前,可以按F12进入bootmanager界面,在此界面下可以选择需要启动的系统。(请原谅我使用手机拍摄屏幕的方......
  • iOS政策解读之一丨App提交审核前注意事项必知
    大家好,我是小编阿文。欢迎您关注我们,经常分享有关Android出海,iOS出海,App市场政策实时更新,互金市场投放策略,最新互金新闻资讯等文章,期待与您共航世界之海。iOS企业出海所面临的主要挑战之一,就是要精读App审核指南,根据出海的目标国家或地区,深刻理解并遵守App审核指南要求,这对于......
  • 开源项目推荐-vue2+element+axios 个人财务管理系统
    文章目录financialmanagement项目简介项目特色项目预览卫星的实现方式:首次进入卫星效果的实现方式:卫星跟随鼠标滑动的随机效果实现方式:环境准备项目启动项目部署项目地址financialmanagement项目简介vue2+element+axios个人财务管理系统是基于vue2+element+ax......
  • 09-axios在Vue中的导入与配置
    09-axios前言首先简单了解什么是Axios?以上完成后就可以使用了前言我们接着上一篇文章08-路由地址的数据获取来讲。下一篇文章10-vuex在Vue中的导入与配置首先简单了解什么是Axios?Axios是一个基于Promise用于浏览器和nodejs的HTTP客户端,本质上也是对......
  • c++提供的类型转换
    在C++中,提供了几种不同的类型转换方式,每种转换方式有其特定的使用场景和语义。以下是C++中常见的几种类型转换方式:静态转换(StaticCast):使用static_cast进行转换,用于基本类型之间的转换,如数值类型的转换、非const对象指针的转换等。静态转换在编译时进行,不提供运行时的检......
  • Flutter 借助SearchDelegate实现搜索页面,实现搜索建议、搜索结果,解决IOS拼音问题
    搜索界面使用Flutter自带的SearchDelegate组件实现,通过魔改实现如下效果:搜素建议搜索结果,支持刷新和加载更多IOS中文输入拼音问题界面预览拷贝源码将SearchDelegate的源码拷贝一份,修改内容如下:import'package:flutter/material.dart';import'package:flutter/servic......
  • ios CCEncoding.m
    ////CCEncoding.h//CCFC////Createdbyxichenon11-12-18.//Copyright2011ccteam.Allrightsreserved.//#import<Foundation/Foundation.h>//"陈曦"的unicode编码为://0x480x960xE60x66//UTF8编码为://......
  • 技嘉BIOS超频设置操作路径
    关闭超线程频率电压控制>进阶处理器设置>Hyper_THreading关小核心频率电压控制>GIGABYTEPerfDrive>EcoreDisable防掉压等级频率电压控制>高级电压设定>处理器/VRM设置>CPUVcoreLoadline校正建议turbo温度墙频率电压控制>进阶处理器设置>......