Swift 专题二 语法速查

一 、变量 let, var

变量是可变的,使用 var 修饰,常量是不可变的,使用 let 修饰。类、结构体和枚举里的变量是属性。

var v1:String = "hi" // 标注类型
var v2 = "类型推导"
let l1 = "标题" // 常量class a {let p1 = 3var p2: Int {p1 * 3}
}

属性没有 set 可以省略 get,如果有 set 需加 get。变量设置前通过 willSet 访问到,变量设置后通过 didSet 访问。

1.1 、计算属性的get和set省略规则

 1.1.1 省略get的情况:
在 Swift 中,对于只读计算属性(即只有获取值的功能,没有设置值的功能),可以省略get关键字。例如,定义一个Rectangle结构体来表示矩形,有一个计算属性area用于计算矩形的面积:

struct Rectangle {let width: Doublelet height: Doublevar area: Double {return width * height}
}

  • 在这个例子中,area是一个计算属性,它只需要返回矩形的面积,不需要设置值,所以可以省略get关键字。当访问area属性时,就会执行花括号内的代码来计算并返回矩形的面积。

1.1.2 set和get同时出现的情况:

如果一个计算属性有set方法(用于设置属性的值),那么必须同时有get方法。例如,假设有一个TemperatureConverter结构体,用于在摄氏温度和华氏温度之间进行转换,其中有一个计算属性celsius,可以设置和获取摄氏温度的值:

struct TemperatureConverter {var fahrenheit: Doublevar celsius: Double {get {return (fahrenheit - 32) * 5 / 9}set {fahrenheit = newValue * 9 / 5 + 32}}
}

  • 在这个例子中,celsius计算属性既有get方法用于获取摄氏温度(通过将华氏温度转换为摄氏温度的公式计算),又有set方法用于设置摄氏温度(通过将摄氏温度转换为华氏温度的公式计算,其中newValue是设置属性时传入的值)。

1.2 属性观察器willSet和didSet的工作原理和使用场景

1.2.1 willSet的工作原理和示例:


willSet是一个属性观察器,它会在属性值被设置之前被调用。它可以访问即将被设置的新值,这个新值默认在willSet块中被命名为newValue。例如,有一个BankAccount类,其中有一个balance属性,当要设置余额时,可以在willSet中添加一些验证逻辑:

class BankAccount {var balance: Double = 0.0 {willSet {if newValue < 0 {print("余额不能为负数")// 可以在这里选择阻止设置负数余额,比如抛出一个错误或者直接返回}}}
}

  • 在这个例子中,当尝试设置balance属性时,willSet块会被调用。如果newValue(即将设置的余额)小于 0,会打印一条错误消息。这样可以在属性值真正被设置之前进行一些预处理或验证操作。

1.2.1 didSet的工作原理和示例:
didSet也是一个属性观察器,它在属性值被设置之后被调用。它可以访问刚刚被设置的旧值,这个旧值默认在didSet块中被命名为oldValue。例如,对于上述的BankAccount类,可以在didSet中添加一些日志记录功能:

class BankAccount {var balance: Double = 0.0 {didSet {print("余额从\(oldValue)更新为\(balance)")}}
}
  • 在这个例子中,每次balance属性被设置后,didSet块就会被调用,打印出余额从旧值(oldValue)更新为新值(balance)的信息。这对于跟踪属性值的变化、更新相关的 UI 或者执行其他依赖于属性值变化的操作非常有用。

 1.3  willSet和didSet的注意事项和应用场景
1.3.1 注意事项:


willSet和didSet观察器对于存储属性和计算属性都适用,但对于计算属性来说,willSet和didSet观察器不会在属性的get和set方法内部被调用,而是在外部直接对计算属性进行设置操作时被调用。
同时,willSet和didSet不能用于常量(用let声明的属性),因为常量的值在初始化后不能被修改,所以没有必要使用属性观察器。

1.3.2 应用场景:


数据验证和预处理:如前面BankAccount示例中,willSet可用于在设置属性值之前进行数据验证,防止不合理的数据被设置。还可以用于对数据进行预处理,例如对输入的数据进行格式化等操作。
UI 更新和状态跟踪:didSet非常适合用于更新用户界面或者跟踪对象的状态变化。在 iOS 或 macOS 应用开发中,当模型对象的属性发生变化时,可以在didSet中触发 UI 的更新,以保持界面和数据的同步。例如,当一个视图模型中的数据属性改变后,在didSet中通知视图进行刷新。
业务逻辑和事件触发:在复杂的业务逻辑中,willSet和didSet可以作为事件触发的机制。例如,在一个库存管理系统中,当商品库存数量属性发生变化时,通过willSet和didSet可以触发重新计算库存价值、检查库存警戒值等相关业务逻辑操作。

二 、打印

print("hi")
let i = 14
print(i)
print("9月\(i)是小柠檬的生日")for i in 1...3{print(i)
}
// output:
// 1
// 2
// 3// 使用terminator使循环打印更整洁
for i in 1...3 {print("\(i) ", terminator: "")
}
// output:
// 1 2 3

三、注释

// 单行注释
/*
多行注释第一行。
多行注释第二行。
*/ 
// MARK: 会在 minimap 上展示
// TODO: 待做
// FIXME: 待修复

四、可选 ?,!

可能会是 nil 的变量就是可选变量。当变量为 nil 通过??操作符可以提供一个默认值。

var o: Int? = nil
let i = o ?? 0
  1. 可选类型(?)的使用情况

    • 定义可选类型

      • 在 Swift 中,?主要用于定义可选类型。当一个变量的值可能存在也可能不存在(即可以是nil)时,就需要将其声明为可选类型。例如,一个文本字段(UITextField)中的文本内容在用户没有输入任何东西时为nil,所以在 Swift 中可以这样声明一个变量来存储文本字段中的内容:var text: String?。这表示text变量是一个可选的String类型,它可以存储一个String值或者nil
    • 安全解包(可选绑定)

      • 当使用可选类型的值时,需要先进行解包。一种安全的方式是使用可选绑定(if letguard let)。例如,if let actualText = text { print(actualText) },这里text是一个可选的String类型,if let语句会检查text是否为nil。如果text不是nil,就将其解包并赋值给actualText变量,然后可以在if语句块中安全地使用actualText变量;如果textnil,则if语句块中的代码不会执行。
    • 可选链调用

      • 当访问可选类型的属性、方法或下标的时候,可以使用可选链(?.)。例如,假设有一个可选的UIView类型的变量view,如果要访问它的backgroundColor属性,可以写成view?.backgroundColor。如果viewnil,整个表达式的值就是nil,不会导致程序崩溃;如果view不是nil,就会正常访问backgroundColor属性。
        class Person {let name: Stringlet age: Int?init(name: String, age: Int?) {self.name = nameself.age = age!}
        }

      • 在这个例子中,假设你在创建Person实例时能够确定age的值不是nil(比如通过其他验证逻辑),就可以使用强制解包。但如果age可能为nil,这种强制解包就会导致程序崩溃,所以使用强制解包时一定要谨慎,确保值不会为nil
    • 总结和注意事项

      • 一般来说,优先推荐使用安全的可选类型处理方式(?相关的操作),因为这可以避免程序因为意外的nil值而崩溃。只有在你非常确定可选类型的值不为nil,并且能够承担程序崩溃的风险(例如在一些内部代码逻辑,你已经进行了严格的验证)时,才考虑使用强制解包(!)。在编写代码时,要尽量减少强制解包的使用,以提高代码的健壮性和稳定性。

            五、闭包

闭包也可以叫做 lambda,是匿名函数,对应 OC 的 block。

let a1 = [1,3,2].sorted(by: { (l: Int, r: Int) -> Bool inreturn l < r
})
// 如果闭包是唯一的参数并在表达式最后可以使用结尾闭包语法,写法简化为
let a2 = [1,3,2].sorted { (l: Int, r: Int) -> Bool inreturn l < r
}
// 已知类型可以省略
let a3 = [1,3,2].sorted { l, r inreturn l < r
}
// 通过位置来使用闭包的参数,最后简化如下:
let a4 = [1,3,2].sorted { $0 < $1 }

函数也是闭包的一种,函数的参数也可以是闭包。@escaping 表示逃逸闭包,逃逸闭包是可以在函数返回之后继续调用的。@autoclosure 表示自动闭包,可以用来省略花括号。

六、函数 func

6.1 函数的基本定义和语法

  • 定义:在 Swift 中,函数是一段独立的、可执行的代码块,用于完成特定的任务。它可以接收输入参数,执行操作,并返回一个结果(也可以没有返回值)。
  • 语法
    • 基本语法是func [函数名]([参数列表]) -> [返回类型] { [函数体] }。例如,定义一个简单的函数用于计算两个整数的和
func add(num1: Int, num2: Int) -> Int {return num1 + num2
}
  • 在这个例子中,func是函数定义的关键字,add是函数名,(num1: Int, num2: Int)是参数列表,其中num1num2是参数名,Int是参数类型。-> Int表示函数的返回类型是整数,{ return num1 + num2; }是函数体,包含了函数要执行的具体代码,在这里是返回两个参数相加的结果。   
  • 6.2、函数参数的多种形式

    • 默认参数值
      • 可以为函数参数设置默认值。例如,定义一个函数用于打印问候语,其中名字参数有默认值:
        func greet(name: String = "World") {print("Hello, \(name)!")
        }

        样,当调用greet()函数时不传入参数,会使用默认值"World",打印Hello, World!;如果传入一个名字参数,如greet(name: "Swift"),则会打印Hello, Swift!

      • 6.3、可变参数

        • 有时候需要函数能够接收不定数量的参数。Swift 允许使用可变参数来实现这一点。例如,定义一个函数用于计算一组整数的总和:
        • func sum(numbers: Int...) -> Int {var result = 0for number in numbers {result += number}return result
          }

          在这个例子中,numbers: Int...表示numbers是一个可变参数,它可以接收任意数量的整数。在函数体中,可以像处理数组一样处理这些可变参数。例如,sum(numbers: 1, 2, 3)会返回6

        • 6.4 函数的返回值

        • 单一返回值
          • 如前面的add函数示例,函数可以返回一个值。返回值的类型在函数定义时通过-> [返回类型]来指定。函数体中使用return关键字来返回结果。如果函数不需要返回值,可以将返回类型指定为Void或者省略->和返回类型部分。例如,一个只打印内容而不返回结果的函数:
          • func printMessage() {print("This is a message.")
            }

          • 多返回值(通过元组)
            • 当需要函数返回多个值时,可以使用元组(Tuple)。例如,定义一个函数用于计算一个整数的平方和立方:
              func squareAndCube(num: Int) -> (square: Int, cube: Int) {let square = num * numlet cube = num * num * numreturn (square, cube)
              }

              在这个例子中,函数squareAndCube返回一个元组,其中包含两个元素,一个是整数的平方,另一个是整数的立方。调用这个函数时,例如let result = squareAndCube(num: 3)result就是一个包含两个整数的元组,可以通过result.square访问平方值,result.cube访问立方值

            • 6.5 函数类型和作为参数传递或返回值

              • 函数类型的概念
                • 每个函数都有一个特定的类型,它由参数类型和返回类型组成。例如,add函数的类型是(Int, Int) -> Int,表示这个函数接收两个整数参数并返回一个整数。
              • 函数作为参数传递
                • 可以将函数作为参数传递给其他函数。例如,定义一个函数用于对两个整数执行某种操作(这个操作通过另一个函数来定义):
                • func operate(num1: Int, num2: Int, operation: (Int, Int) -> Int) -> Int {return operation(num1, num2)
                  }

                • 在这里,operate函数的第三个参数operation是一个函数类型,它接收两个整数参数并返回一个整数。可以这样调用operate函数:let result = operate(num1: 3, num2: 4, operation: add),其中add是前面定义的用于计算两个整数相加的函数。
                • 函数作为返回值返回
                  • 函数也可以作为返回值返回。例如,定义一个函数用于返回一个根据给定条件计算的函数:
                    func getCalculator(operation: String) -> (Int, Int) -> Int {if operation == "add" {return add} else if operation == "subtract" {return subtract} else {fatalError("Invalid operation")}
                    }

                  • 在这个例子中,getCalculator函数根据传入的操作字符串返回一个相应的计算函数(如add函数或subtract函数)。这样,就可以根据不同的需求获取不同的计算函数,增加了代码的灵活性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/68715.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql查看binlog日志

mysql 配置、查看binlog日志&#xff1a; 示例为MySQL8.0 1、 检查binlog开启状态 SHOW VARIABLES LIKE ‘log_bin’; 如果未开启&#xff0c;修改配置my.ini 开启日志 安装目录配置my.ini(mysql8在data目录) log-binmysql-bin&#xff08;开启日志并指定日志前缀&#xff…

某国际大型超市电商销售数据分析和可视化

完整源码项目包获取→点击文章末尾名片&#xff01; 本作品将从人、货、场三个维度&#xff0c;即客户维度、产品维度、区域维度&#xff08;补充时间维度与其他维度&#xff09;对某国际大型超市的销售情况进行数据分析和可视化报告展示&#xff0c;从而为该超市在弄清用户消费…

Linux 存储设备和 Ventoy 启动盘制作指南

一、Linux 存储设备基础知识 1. 设备路径&#xff08;/dev&#xff09; 设备路径是 Linux 系统中物理存储设备的唯一标识&#xff0c;类似设备的"身份证号"。 命名规则解析 /dev/sda&#xff1a; /dev&#xff1a;device&#xff08;设备&#xff09;的缩写&…

PostgreSQL-01-入门篇-简介

文章目录 1. PostgreSQL是什么?2. PostgreSQL 历史 2.1. 伯克利 POSTGRES 项目2.2. Postgres952.3. PostgreSQL来了 3. PostgreSQL vs MySQL4. 安装 4.1 Windows 安装4.2 linux 安装4.3 docker安装 1. PostgreSQL是什么 PostgreSQL 是一个基于加州大学伯克利分校计算机系开…

数仓建模:当DWS构建好后,突然来了一个新的需求,需要添加某个或某几个维度字段时,应该如何处理?

目录 1. 需求评估与分析 2. 表结构调整 3. ETL 流程修改 4. 数据更新和回填 5. 数据分析和报表调整

Git原理与应用(三)【远程操作 | 理解分布式 | 推送拉取远程仓库 | 标签管理】

Git 理解分布式版本控制系统远程仓库新建远程仓库克隆远程仓库向远程仓库推送配置Git忽略特殊文件 标签管理理解标签创建标签操作标签删除标签 理解分布式版本控制系统 我们⽬前所说的所有内容&#xff08;工作区&#xff0c;暂存区&#xff0c;版本库等等&#xff09;&#x…

TCP创建通信前的三次握手(为啥不是两次?)

1.三次握手的过程 客户端发送 SYN&#xff08;同步&#xff09;报文 客户端向服务器发送 SYN 标志的数据包&#xff0c;请求建立连接&#xff0c;表示 "你好&#xff0c;我要连接你"。 服务器回复 SYNACK&#xff08;同步确认&#xff09;报文 服务器收到 SYN 后&am…

一文夯实垃圾收集的理论基础

如何判断一个引用是否存活 引用计数法 给对象中添加一个引用计数器&#xff0c;每当有一个地方引用它&#xff0c;计数器就加 1&#xff1b;当引用失效&#xff0c;计数器就减 1&#xff1b;任何时候计数器为 0 的对象就是不可能再被使用的。 优点&#xff1a;可即刻回收垃圾&a…

回归算法、聚类算法、决策树、随机森林、神经网络

这也太全了&#xff01;回归算法、聚类算法、决策树、随机森林、神经网络、贝叶斯算法、支持向量机等十大机器学习算法一口气学完&#xff01;_哔哩哔哩_bilibili 【线性回归、代价函数、损失函数】动画讲解_哔哩哔哩_bilibili 14分钟详解所有机器学习算法&#xff1a;…

Spring Boot 配置(官网文档解读)

目录 摘要 Spring Boot 配置加载顺序 配置文件加载顺序 Spring Boot 配置加载方式 Value Value 注解简单示例 ConfigurationProperties 启动 ConfigurationProperties ConfigurationProperties 验证 ConfigurationProperties 与 Value 对比 Autowired Autowired 自…

机器学习-基本术语

文章目录 1. **数据集&#xff08;Dataset&#xff09;**2. **样本&#xff08;Sample&#xff09;**3. **属性&#xff08;Attribute&#xff09;**4. **特征&#xff08;Feature&#xff09;**5. **属性值&#xff08;Attribute Value&#xff09;**6. **属性空间&#xff08…

一款功能强大的互联网资产测绘引擎-CyberEdge

声明&#xff01;本文章所有的工具分享仅仅只是供大家学习交流为主&#xff0c;切勿用于非法用途&#xff0c;如有任何触犯法律的行为&#xff0c;均与本人及团队无关&#xff01;&#xff01;&#xff01; 目录标题 CyberEdge简洁而强大的互联网资产测绘工具核心特性搭建指南快…

细说STM32F407单片机电源低功耗StopMode模式及应用示例

目录 一、停止模式基础知识 1、进入停止模式 2、停止模式的状态 3、退出停止模式 4、SysTick定时器的影响 二、停止模式应用示例 1、示例功能和CubeMX项目配置 &#xff08;1&#xff09;时钟 &#xff08;2&#xff09;RTC &#xff08;3&#xff09;ADC1 &#xf…

【三国游戏——贪心、排序】

题目 代码 #include <bits/stdc.h> using namespace std; using ll long long; const int N 1e510; int a[N], b[N], c[N]; int w[4][N]; int main() {int n;cin >> n;for(int i 1; i < n; i)cin >> a[i];for(int i 1; i < n; i)cin >> b[i…

[Qt]事件-鼠标事件、键盘事件、定时器事件、窗口改变事件、事件分发器与事件过滤器

目录 前言&#xff1a;Qt与操作系统的关系 一、Qt事件 1.事件介绍 2.事件的表现形式 常见的Qt事件&#xff1a; 常见的事件描述: 3.事件的处理方式 处理鼠标进入和离开事件案例 控件添加到对象树底层原理 二、鼠标事件 1.鼠标按下和释放事件&#xff08;单击&#x…

【优选算法】----移动零

好久没写博客的兄弟姐妹们~ 今天来写一篇算法过过水吧~ --------------------------------------begin---------------------------------------- 题目要求&#xff1a; 给的难度是简单哦 题目解析&#xff1a; 这道题的思路可以借助双指针的思想&#xff0c;定义dest和c…

Java设计模式—观察者模式

观察者模式 目录 观察者模式1、什么是观察者模式&#xff1f;2、观察者模式优缺点及注意事项&#xff1f;3、观察者模式实现&#xff1f;4、手写线程安全的观察者模式&#xff1f; 1、什么是观察者模式&#xff1f; - 实例&#xff1a;现实生活中很多事物都是依赖存在的&#x…

使用Sum计算Loss和解决梯度累积(Gradient Accumulation)的Bug

使用Sum计算Loss和解决梯度累积的Bug 学习 https://unsloth.ai/blog/gradient&#xff1a;Bugs in LLM Training - Gradient Accumulation Fix 这篇文章的记录。 在深度学习训练过程中&#xff0c;尤其是在大批量&#xff08;large batch&#xff09;训练中&#xff0c;如何高…

WGAN - 瓦萨斯坦生成对抗网络

1. 背景与问题 生成对抗网络&#xff08;Generative Adversarial Networks, GANs&#xff09;是由Ian Goodfellow等人于2014年提出的一种深度学习模型。它包括两个主要部分&#xff1a;生成器&#xff08;Generator&#xff09;和判别器&#xff08;Discriminator&#xff09;…

Qt 5.14.2 学习记录 —— 십칠 窗口和菜单

文章目录 1、Qt窗口2、菜单栏设置快捷键添加子菜单添加分割线和菜单图标 3、工具栏 QToolBar4、状态栏 QStatusBar5、浮动窗口 QDockWidget 1、Qt窗口 QWidget&#xff0c;即控件&#xff0c;是窗口的一部分。在界面中创建控件组成界面时&#xff0c;Qt自动生成了窗口&#xf…