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
-
可选类型(
?)的使用情况-
定义可选类型:
- 在 Swift 中,
?主要用于定义可选类型。当一个变量的值可能存在也可能不存在(即可以是nil)时,就需要将其声明为可选类型。例如,一个文本字段(UITextField)中的文本内容在用户没有输入任何东西时为nil,所以在 Swift 中可以这样声明一个变量来存储文本字段中的内容:var text: String?。这表示text变量是一个可选的String类型,它可以存储一个String值或者nil。
- 在 Swift 中,
-
安全解包(可选绑定):
- 当使用可选类型的值时,需要先进行解包。一种安全的方式是使用可选绑定(
if let或guard let)。例如,if let actualText = text { print(actualText) },这里text是一个可选的String类型,if let语句会检查text是否为nil。如果text不是nil,就将其解包并赋值给actualText变量,然后可以在if语句块中安全地使用actualText变量;如果text是nil,则if语句块中的代码不会执行。
- 当使用可选类型的值时,需要先进行解包。一种安全的方式是使用可选绑定(
-
可选链调用:
- 当访问可选类型的属性、方法或下标的时候,可以使用可选链(
?.)。例如,假设有一个可选的UIView类型的变量view,如果要访问它的backgroundColor属性,可以写成view?.backgroundColor。如果view是nil,整个表达式的值就是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)是参数列表,其中num1和num2是参数名,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函数)。这样,就可以根据不同的需求获取不同的计算函数,增加了代码的灵活性。
- 函数也可以作为返回值返回。例如,定义一个函数用于返回一个根据给定条件计算的函数:
- 函数类型的概念:
- 当需要函数返回多个值时,可以使用元组(Tuple)。例如,定义一个函数用于计算一个整数的平方和立方:
- 如前面的
- 可以为函数参数设置默认值。例如,定义一个函数用于打印问候语,其中名字参数有默认值:
- 默认参数值:
相关文章:
Swift 专题二 语法速查
一 、变量 let, var 变量是可变的,使用 var 修饰,常量是不可变的,使用 let 修饰。类、结构体和枚举里的变量是属性。 var v1:String "hi" // 标注类型 var v2 "类型推导" let l1 "标题" // 常量class a {…...
Api网关Zuul
网关分类与开放API 开放API (OpenAPI) 企业需要将自身数据、能力等作为开发平台向外开放,通常会以REST的方式向外提供,最好的例子就是淘宝开放平台、腾讯公司的QQ开发平台、微信开放平台。开放API平台必然涉及到客户应用的接入、API权限的管理、调用次数…...
01设计模式(D3_设计模式类型 - D3_行为型模式)
目录 一、模版方法模式 1. 基本介绍 2. 应用案例一:豆浆制作问题 需求 代码实现 模板方法模式的钩子方法 3. View的draw(Android) Android中View的draw方法就是使用了模板方法模式 模板方法模式在 Spring 框架应用的源码分析 知识小…...
python编程-OpenCV(图像读写-图像处理-图像滤波-角点检测-边缘检测)角点检测
角点检测(Corner Detection)是计算机视觉和图像处理中重要的步骤,主要用于提取图像中的关键特征,以便进行后续的任务,比如图像匹配、物体识别、运动跟踪等。下面介绍几种常用的角点检测方法及其应用。 1. Harris角点检…...
费解的开关
费解的开关 你玩过“拉灯”游戏吗? 25 盏灯排成一个 55 的方形。 每一个灯都有一个开关,游戏者可以改变它的状态。 每一步,游戏者可以改变某一个灯的状态。 游戏者改变一个灯的状态会产生连锁反应:和这个灯上下左右相邻的灯也…...
【机器学习】机器学习引领数学难题攻克:迈向未知数学领域的新突破
我的个人主页 我的领域:人工智能篇,希望能帮助到大家!!!👍点赞 收藏❤ 一、引言 在数学的浩瀚领域中,存在着诸多长期未解的难题,这些难题犹如高耸的山峰,吸引着无数数…...
Qt之QDjango-db的简单使用
QDjango是一款由C编写、依托于Qt库的Web开发框架,其设计理念受到了广受欢迎的Python框架Django的影响。这个项目旨在提供一个高效、灵活且易于使用的工具集,帮助开发者构建高质量的Web应用。其项目地址: https://gitcode.com/gh_mirrors/qd/qdjango&…...
缓存、数据库双写一致性解决方案
双写一致性问题的核心是确保数据库和缓存之间的数据同步,以避免缓存与数据库数据不同步的问题,尤其是在高并发和异步环境下。本文将探讨双写一致性面临的主要问题和解决方案,重点关注最终一致性。 本文讨论的是最终一致性问题 双写一致性面…...
SUnet: A multi-organ segmentation network based on multiple attention【医学图像分割】
一、论文信息 1.1、中文名称 名称:SUnet:基于多重注意力的多器官分割网络 1.2、论文关键词 医学图像分割、Transformer、注意力机制、高效特征融合模块 1.3、核心概述 本文提出了一种新颖有效的医学图像分割方法 SUnet,用于腹部和胸部的多…...
uniapp实现“到这儿去”、拨打电话功能
"到这儿去" 在 UniApp 中实现“到这儿去”的功能,即调起地图导航至指定位置,对于不同的平台(小程序、H5、App)有不同的处理方式。下面将简单介绍如何在这些平台上实现该功能,并讨论位置信息的获取。后面需求会用到,先来找一些相关资料,并不一定很准确,但也来…...
2025年入职/转行网络安全,该如何规划?网络安全职业规划
网络安全是一个日益增长的行业,对于打算进入或转行进入该领域的人来说,制定一个清晰且系统的职业规划非常重要。2025年,网络安全领域将继续发展并面临新的挑战,包括不断变化的技术、法规要求以及日益复杂的威胁环境。以下是一个关…...
【博客之星】2024年度个人成长、强化学习算法领域总结
📢在2025年初,非常荣幸能通过审核进入到《2024年度CSDN博客之星总评选》TOP300的年度评选中,排名40。这还是第一次来到这个阶段,作为一名博士研究生,还是备受鼓舞的。在这里我将以回顾的方式讲述一下这一年在CSDN中走过…...
HTML5 Canvas实现的跨年烟花源代码
以下是一份基于HTML5 Canvas实现的跨年烟花源代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml">…...
使用通用预训练范式为 3D 基础模型铺平道路
大家读完觉得有帮助记得关注和点赞!!!,本次是英文需要英文功底扎实的阅读。 Abstract In contrast to numerous NLP and 2D vision foundational models, learning a 3D foundational model poses considerably greater challenge…...
SpringMVC (2)
目录 1. RequestMapping 注解介绍 2. RequestMapping 使用 3. RequestMapping与请求方式 3.1 RequestMapping 支持Get和Post类型的请求 3.2 RequestMapping 指定接收某种请求 3.3 GetMapping和PostMapping 4. 传参 4.1 通过查询字符串传参 4.2 在 Body 中传参 4.2.1 …...
【Vim Masterclass 笔记16】S07L32 + L33:同步练习09 —— 掌握 Vim 宏操作的六个典型案例(含点评课内容)
文章目录 S07L32 Exercise 09 - Macros1 训练目标2 操作指令2.1. 打开 macros-practice.txt 文件2.2. 练习1:将旧版 Python 代码转换为新版写法2.3. 练习2:根据列表内容批量创建 Shell 脚本2.4. 练习3:对电话号码作格式化处理2.5. 练习4&…...
爬楼梯问题(Leetcode 第70题)
爬楼梯问题(Leetcode 第70题) 问题描述 假设你正在爬楼梯。每次你可以爬 1 个或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 示例 1: 输入:n 2 输出:2 解释:有两种方法可以爬到楼顶。…...
6.5 正定矩阵
一、正定矩阵 这一节关注的是特征值都是正数的对称矩阵。如果对称使得矩阵很重要,那么这个额外的性质(所有的 λ > 0 \lambda>0 λ>0)会使得它更加的特殊。我们所说的特殊并不表示它稀有,特征值都是正数的对称矩阵几乎…...
verilog笔记1
1. 阻塞赋值 阻塞赋值,顾名思义即在一个 always 块中,后面的语句会受到前语句的影响,具体来说就是在同一个always 中,一条阻塞赋值语句如果没有执行结束,那么该语句后面的语句就不能被执行,即被“阻塞”。也…...
游戏引擎学习第81天
仓库:https://gitee.com/mrxiao_com/2d_game_2 或许我们应该尝试在地面上添加一些绘图 在这段时间的工作中,讨论了如何改进地面渲染的问题。虽然之前并没有专注于渲染部分,因为当时主要的工作重心不在这里,但在实现过程中,发现地…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
群晖NAS如何在虚拟机创建飞牛NAS
套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...
go 里面的指针
指针 在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样: a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10,通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...
CppCon 2015 学习:REFLECTION TECHNIQUES IN C++
关于 Reflection(反射) 这个概念,总结一下: Reflection(反射)是什么? 反射是对类型的自我检查能力(Introspection) 可以查看类的成员变量、成员函数等信息。反射允许枚…...
第22节 Node.js JXcore 打包
Node.js是一个开放源代码、跨平台的、用于服务器端和网络应用的运行环境。 JXcore是一个支持多线程的 Node.js 发行版本,基本不需要对你现有的代码做任何改动就可以直接线程安全地以多线程运行。 本文主要介绍JXcore的打包功能。 JXcore 安装 下载JXcore安装包&a…...
基于小程序老人监护管理系统源码数据库文档
摘 要 近年来,随着我国人口老龄化问题日益严重,独居和居住养老机构的的老年人数量越来越多。而随着老年人数量的逐步增长,随之而来的是日益突出的老年人问题,尤其是老年人的健康问题,尤其是老年人产生健康问题后&…...
