swift基础语法

常量和变量

swift 复制代码
import Foundation

print("Hello, World!")

//变量的声明
var name = "zhangsan"
name = "zhuxian"
print(name)

var a = 3, b = 4
var 姓名 = "里斯"
var 😀 = "赵云"
print(姓名, 😀)

//常量的声明
let pi = 3.14
//pi = 2//err
print(pi)

类型安全和类型推断

swift 复制代码
import Foundation

print("Hello, World!")

var age = 30
age = "nihao" //err,类型安全

var a = "中国"
var b = 3
var c = 3.0
var d = true

//会自动推倒数据类型
print(type(of: a))//String
print(type(of: b))//Int
print(type(of: c))//Double
print(type(of: d))//Bool

print函数

swift 复制代码
import Foundation

var name = "zhangsan"
var age = 40
print(name, age)

//separator:分隔符
//terminator:终止符,可终止换行
print(1,2,3,"a",true, 4.23, separator: "-", terminator: " ")
print("=====")

print的使用

swift 复制代码
import Foundation

print("Hello, World!")
//字符串的构造
var name = "zhangxiaofan"
var t1 = ""
var t2 = String()
var t3 = String(repeating: "a", count: 4);//重复构造a四次
print(t3)

//使用"""包裹,可分行输出
var t4 = """
中国
人民
站起来了
"""
print(t4)

//使用\把分行输出的合成一行
var t5 = """
中国\
人民\
站起来了
"""
print(t5)

//想要输出字符串里的字符
var t6 = "\"长高\""//用转义
print(t6)

var t7 = #""中国""# //用两个#"
print(t7)

字符串的操作

swift 复制代码
import Foundation

print("Hello, World!")

var name = "张三"
var age = 30
var str = "是个好同志"

print(name + str) //字符串拼接
print(name.appending(str))
//name += str //会改变name
//print(name)


print(name.isEmpty)//判断串是否为空
print(name.count)//返回字符串的长度

print(name.description)//返回字符串的内容
print(name.debugDescription)//返回便于调试的字符串的内容

print(name.hashValue)//返回字符串的哈希值,每个变量都有唯一ID,叫做哈希值

var str1 = "This is a Test"
print(str1.lowercased())//把字符都变为小写
print(str1.uppercased())//把字符都变为大写


//字符串的比较,根据ascii表进行比较
print("ab" == "ab")
print("ab" != "ab")

//判断字符串是否包含某个前后缀字符串
print("productNum".hasPrefix("pro"))
print("productNum".hasSuffix("Num"))


//字符串的遍历
//1.for循环
var str2 = "abc是中国人🇨🇳"
//for c in str2{
//    print(c)
//}

//2用下标进行遍历
//for index in str2.indices{
//    print(str2[index], index)
//}

//随机访问某个字符
print(str2[str2.startIndex])
print(str2[str2.index(before:str2.endIndex)])//最后一个位置的前一位
print(str2[str2.index(str2.endIndex, offsetBy: -2)])

整数

swift 复制代码
import Foundation

//整数
//Int
//Double
//Float
//var a = 4
//var b = 4.0
//print(type(of: a)) //Int
//print(type(of: b)) //Double
//var c:Float = 3.4 //浮点数要这样定义
//print(type(of: c)) //Float


var age = 40
var myAge:Int = 50 //显示指定
var yourAge = Int(60.0) //类型转换
var a = +10
var b = -5
//print(a, b)

//定义不同进制的数
var c = 0b10 //二进制
var d = 0o7 //8进制
var e = 0xf //16进制
//print(c, d, e);

//千位分隔符
var f = 89_000_000
//print(f)

//随机生成整数
//print(Int.random(in: 1...100))//随机生成[1,100]的数
//print(Int.random(in: 100..<110))//随机生成[100,110)的数

//整数的相关运算
//+ - * / ==  !=

//整数的其他方法
var x = -20
x.negate() //取x的相反数
//print(x)

x = -30
//print(x.magnitude)//取x的绝对值(推荐)
//print(abs(-40))//取x的绝对值

//求一个整数的商和余数
var g = 100
let (q, r) = g.quotientAndRemainder(dividingBy: 9)
//print(q, r) //商为11,余数为1

//判断一个整数的符号
print(x.signum()) //正数为1, 0就是0, 负数为-1


//整数的常量调用
//print(Int.zero)
//print(Int.max)
//print(Int.min)


//整数的描述方法和哈希值,同字符串

双精度

swift 复制代码
import Foundation

//Double
//var x = 10.0
var y:Double = 20.0 //显示声明
var z = Double (2) //整数转双精度
print (x,y,z)

//生成随机数
var z1 = Double.random(in:10.0...100.0)
print(z1) //63.25634290900475

print(z1.squareRoot())//平方根 7.504985299853613

//print(z1.rounded())
//print(z1.rounded(.awayFromZero))

//四舍五入的规则
var x = 100.23
print(x.rounded(.awayFromZero))//四舍五入到幅度大于或等于源值的最接近的允许值
print(x.rounded (.down))//四舍五入为小于或等于源值的最接近的允许值。
print(x.rounded(.toNearestOrAwayFromZero))//四舍五入到最接近的允许值;如果两个值同样接近,则选择幅度较大的一个。
print(x.rounded(.toNearestOrEven))//四舍五入到最接近的允许值;如果两个值同样接近,则选择偶数。
print(x.rounded (.towardZero))//四舍五入到幅度小于或等于源值的最接近的允许值。
print(x.rounded(.up))//四舍五入为大于或等于源值的最接近的允许值。

y = -1.1
print(y.magnitude)//绝对值

print(y.sign) //符号 正数为plus, 负数为minus

print(Double.pi) //3.141592653589793|

布尔值

swift 复制代码
import Foundation

//Boo1
var x = true
var y: Bool = false

x.toggle() //取反
print (x)

print(Bool.random())//随机bool值

//Bool的描述和哈希值
print(x.description)
print(x.hashValue)

运算符

swift 复制代码
import Foundation

print("Hello, World!")

//一元运算符
//二元运算符

//算术运算符

//比较运算符

//空合运算符
//左边可选非nil --> 返回左边值
//左边可选nil --> 返回右边默认值

//语法:可选值 ?? 默认值
//注意:
//左边必须是 Optional(如String?、Int?)
//右边类型必须和左边解包后类型一致
//返回值是非可选类型
var name: String? = nil
let displayName = name ?? "游客"
print(displayName) // 游客

name = "张三"
let displayName2 = name ?? "游客"
print(displayName2) // 张三

//区间运算符
//1...10  [1 10]
//1..<10  [1 10)
//...10   在运算时不能用这个开盒的

//逻辑运算符

小练习-计算圆的面积和周长

swift 复制代码
import Foundation

//计算圆的面积和周长
print("请输入圆的半径:", terminator: " ")
//readLine函数:可从终端读取数据,类型时可选String
var value = readLine() ?? "0.0" //可能不输入,为空,所以用空合

var radius:Double = 0.0
radius = Double(value) ?? 0.0 //把String转换成Double

let area = Double.pi * radius * radius
let perimeter = 2 * Double.pi * radius

print("半径为\(radius)的圆,周长是:\(perimeter.rounded()),面积是:\(area.rounded())")

数组

数组的声明和遍历方法

swift 复制代码
import Foundation

//数组的声明
var a = [1,2,3]
var b = ["a", "b", "c", "d", "e"]
var c = [true, false, true]
//print(a, b, c)

var a1:Array<Int> = [1,2] //完整写法
var a2:[Int] = [1,2]
//print(a1, a2)

var b1 = Array<Int>() //声明空数组
var b2 = Array<Int>([1,2])
var b3 = Array(1...7)
//print(b1, b2, b3)

var c1 = Array(repeating: "UU", count: 4)
print(c1)
//print(c1.count)//统计元素个数
//print(c1.isEmpty)//判断是否为空

//数组的遍历
//通过下标访问
//print(a[0])
//
//print(b[0...2])
//print(b[...2])//从下标0到下标2
//print(b[1...])//从下标1到结束

//用for循环进行遍历
for ch in b{
    print(ch, terminator: "-")
}
print("")

//用下标进行遍历
//b.enumerated()
//把数组 b 变成 (下标,元素) 的一对一对数据
for(index, value) in b.enumerated(){
    print(index, value,separator: ":")
}

数组的插入和替换

swift 复制代码
import Foundation

var fruit = ["苹果","香蕉","橙子","菠萝","榴莲"]

//输出第一个元素和第二个元素
//print(fruit[0])
//print(fruit[fruit.count-1])
//print(fruit.first ?? "")//防止为空数组所以用空合运算
//print(fruit.last ?? "")

//随机选择一个元素
//print(fruit.randomElement() ?? "")

//给数组追加元素
fruit.append("juzi")//添加一个
//print(fruit)

fruit.append(contentsOf: ["apple","orange"])//添加多个
//print(fruit)

fruit += ["1234"]
//print(fruit)


//给数组插入元素
fruit.insert("叶子", at: 0)//指定位置插入一个
//print(fruit)

fruit.insert(contentsOf: ["x","s"], at: 0)//指定位置插入多个
//print(fruit)

//var n = [12,34,56,67]
//n.insert(contentsOf: 1...3, at: 1)//插入区间序列
//print(n)


//数组元素的替换
fruit.replaceSubrange(1...2, with: ["e","f"])//区间替换元素
//print(fruit)

数组的删除和查找

swift 复制代码
import Foundation

var fruit = ["青苹果","香蕉","桃","李子","榴莲","李子"]

var num = [4, 2, 2,7,9,6]

//区间+数组   数组+区间   区间+区间
var num1 = (1...3) + num
//print (num1)
//var num2 = num + (7...9)
//print (num2)
//print(num1 + num2)

//删除数组元素
//fruit.remove(at: 0)//删除指定元素
//fruit.removeFirst()//删除第一个元素
//fruit.removeLast()//删除最后一个
//fruit.removeSubrange (1...2)//删除指定区间的元素
//fruit.removeA11()//全部删除

//数组的查找
//print (fruit)
//var isli = fruit.contains("apple")//判断数组中是否包含
//print(isli)

//first(where:) = 查找第一个满足条件的元素
//$0 = 数组里当前正在检查的元素(相当于每一个元素)
//$0 == "李子" = 判断当前元素是不是 李子
//结果:
//如果数组里有李子 → 返回 "李子"
//如果数组里没有李子 → 返回 nil
var isli = fruit.first(where:{$0 == "李子"})
//print(isli ?? "")

//var n1 = num.first(where: {$0 > 5})
//print(n1 ?? "")
//也可以不用$0,{n in n > 5}是闭包条件
var n1 = num.first(where: {n in n > 5})//找到数组中大于5的第一个元素
//print(n1 ?? "")

var i = num.firstIndex(where: {n in n > 5})//找到数组中大于5的第一个元素下标
//print(i ?? "")


//找最大值和最小值
print(num.max() ?? "")
print(num.min() ?? "")

数组的其他操作

swift 复制代码
import Foundation

var fruit = ["青苹果","香蕉","桃","李子","榴莲","李子"]

var num = [4, 2, 2,7,9,6]

//数组的变换
let t = ["ZhangSan","LiSi","WangWu","ZhaoLiu"]

var t1 = t.map{
//    $0.lowercased();//把数组元素全部转小写
    $0.uppercased();//把数组元素全部转大写
}
//print(t1)

//使用自己的属性方法遍历
//fruit.forEach{
//    print($0)
//}


//数组的排序
//print(num)
num.sort()//默认排升序
//print(num)

num.sort(by: >)//排降序
//print(num)


//数组的洗牌打乱
//print(fruit)
//fruit.shuffle()
//print(fruit)


//数组的反转
//var s1 = fruit.reversed()//反转后形成一个新数组
//print(s1)
//print(fruit)

//fruit.reverse()//反转后改变原数组
//print(fruit)


//分割字符串放入数组中
let line = "apple orange banana"
//只有一种分隔符时
var l1 = line.split(separator: " ")
//print(l1)

//有多种分隔符时,需要自定义分隔条件
let line1 = "apple+orange banana"
var l2 = line.split(whereSeparator: {
    $0 == "+" || $0 == " "
})
//print(l2)


//把数组变成字符串
print(fruit.joined())
print(fruit.joined(separator: "-"))

Set集合

swift 复制代码
import Foundation

//集合set:里面的元素没有顺序,统一类型,内容不能重复的
//如果有重复元素,输出时会过滤掉重复元素

//Set的声明
var s:Set<Int> = [1,2,3,4]//这个s是一个set集合,集合里是Int类型的元素
var s1 = Set([1,2,3,4]);
//print(s, s1)


var a = Set(["苹果","香蕉","桔子","柚子","橙子"])
var b = Set(["桃子","香蕉","桔子","甜瓜","西瓜"])
var c = Set(["苹果"])

//Set的相关方法
//print(a.count) //元素个数
//print(a.isEmpty)//是否为空


//set的插入
//插入时有两个返回值,
//若插入不重复元素,返回(true,插入的元素)
//若插入重复元素,返回(false,插入的元素)
//输出多次会发现,每次插入的位置是随机的
//var (c,d) = a.insert("栗子")
//print(c,d)
//print(a)

//a.update(with: "apple")//强行插入
//print(a)


//set的删除
//a.remove("apple")//删除一个元素
//print(a)
//a.removeAll()//删除所有元素


//集合的四种运算
//有两个集合 a 和 b ,求 a+b,a-b,a交集b, 所有-a交集b的部分
//print(a.union(b))//加,重复元素过滤掉
//print(a.subtracting(b))//减,在集合a中,减去a和b的重复部分
//print(a.intersection(b))//a和b共有的部分
//print(a.symmetricDifference(b))//加的结果-共有的部分


//print(c.isSubset(of: a))//判断c是不是a的子集
//print(a.isSuperset(of: c))//判断a是否包含c(超集)

//集合的随机元素
//print(a.randomElement() ?? "")


//集合的变换,同数组
//.map
//.sort
//.shuffled

//集合的遍历
//a.forEach{
//    print($0)
//}
//
//for ch in a {
//    print(ch)
//}
//
//for(k, v) in a.enumerated() {
//    print(k, v)//这里的下标没有意义
//}

字典

swift 复制代码
//
//  main.swift
//  sf15
//
//  Created by test on 2026/5/29.
//

import Foundation

//字典的声明
var a:Dictionary<Int, String> = [:]//声明空字典,要加:
var b:Dictionary<Double, String> = [23.3:"zhansan"]
var c = ["zhansn":"pingg", "lisi":"栗子"]

//通过key找value
//print(c["lisi", default: ""])

//字典的相关方法
//print(c.count)//有几个键值对
//print(c.isEmpty)//判断是否为空

//字典的遍历
//for(k, v) in c{
//    print(k, v)//输出键值对
//}
//
//for key in c.keys{
//    print(key)//只想输出key值
//}
//
//for v in c.values{
//    print(v)//只想输出value
//}

//c.forEach {
//    print($0,$1)
//}


//字典的随机元素
//print(c.randomElement() ?? "")
//如果不用空合运算,就用一个值接收它,就没有警告了
var ret = c.randomElement()
//print(ret)

区间

swift 复制代码
import Foundation

var a = 5...10 //ClosedRange<Int>
var b = 1..<3 //Range<Int>
var c = ...3 //PartialRangeThrough<Int>
var d = ..<3 //PartialRangeUpTo<Int>
var e = 1... //PartialRangeFrom<Int>
var f = "a"..."z"
var g = 0.0...10.0

//10 12 14 ...
var h = stride(from: 10, to: 100, by: 2) //StrideTo<Int>

//print(type(of: a))
//print(type(of: b))
//print(type(of: c))
//print(type(of: d))
//print(type(of: e))
//print(type(of: f))
//print(type(of: g))
//print(type(of: h))


//区间的完整定义
//var r1:Range<Int> = 1..‹3
//var r2:ClosedRange<Int> = 1...3

//区间的遍历
//半开区间不支持遍历,只有整型的闭合区间才能遍历
//for i in a{
//    print(i)
//}

//判断区间中是否含某个值
//半开区间,非整型也支持
print(a.contains(9))

print(a.count)//区间的个数,半开区间不支持
print(a.isEmpty)//判断是否为空

//区间的上下限
print(a.lowerBound)
print(a.upperBound)

元组

swift 复制代码
import Foundation

//元组的声明
var p = (12,34)
var p1:(Int,Int) = (45,67)

var p2 = ("zhansan", 56,89, 46.89, true)

var position = (x:30, y:40)//也可以这样定义,方便观看
print(position)//(x: 30, y: 40)


var p3 = (name: "3K=", yuwen:80, shuxue:50 , wuli:90, ping:34.5, shengji: true)
print(p3)

//可以访问单个元素
//print(p.0)
//print(position.x)
//print(p3.name)
//print(p3.0)


//元组的解构赋值
//let (x, y) = position
//print(x, y)//30 40

let (x, _) = position//也可以打印一个,另一个要用_占位
print(x)//30

可选类型

swift 复制代码
import Foundation

//可选类型的声明
//var a:String? = "a"//类型+?
//print(type(of: a))//Optional<String>
//
//var b:Optional<String> = "a"
//
////有两个值,一个是Int,很多some,另一个是nil
//var a1:Int? = Optional.some(23)
//print(a1!) //确定不是空,可解包


var a:Int? = 11

//这里可能有空,不能直接这样比
//if(a > 10){
//    print("a大于10")
//}

//正确写法:使用if或者while可以进行判断是否有值,这个过程叫做 可选绑定
//if let b = a //如果a能转换成b的话

//if let b = a{
//    print("你好")//你好
//}

//下面的写法就算a=nil,也不会报错或是警告
//if let b = a{
//    if(b > 10){
//        print("a大于10")
//    }
//}

//var a:Int? = nil
//if let b = a{
//    print("你好")//什么都没有打印
//}


//var s:String = "ProductA"
//print(s.hasPrefix("Product"))

var s:String? = "ProductA"
//print(s?.hasPrefix("Product"))//这样会报警告

//if let b = s?.hasPrefix("Product"){
//    print("有这个前缀",b)
//}

var num = Int("111")
print(num ?? "")

循环语句

swift 复制代码
import Foundation

//for循环语句不在演示,前面遍历时已用过多次

var index = 1

//while(index <= 10){
//    print("你好\(index)")
//    index += 1
//}

//相当于C++里的do..while
repeat{
    print("你好\(index)")
    index += 1
}while index <= 10

条件语句

swift 复制代码
import Foundation

//常用三目运算符进行判断
var score = 99
//var ret = score >= 60 ? "及格" : "不及格"
//print(ret)

//if语句不在演示

switch语句

swift 复制代码
//
//  main.swift
//  sf21
//
//  Created by test on 2026/5/29.
//

import Foundation

//在 Swift 中,当匹配的 case 分支中的代码执行完毕后,程序会终止 switch 语句,而不会继续执行下一个 case 分支。这也就是说,不需要在 case 分支中显式地使用 break 语句。如果需要产生case穿透,则可以在case结束后,增加fallthrough,它所在的case不会被执行

//var score = 87
//switch score {
//case 100://单值
//    print("牛x")
//case 90...99://区间
//    print("完美")
//case 80,81,82,83,84,85,86,97,88,89://多值
//    print("优秀")
//case 60..<80:
//    fallthrough
//    print("合格")
//default:
//    print("不及格")
//}

//像上面这样罗列有点繁琐
//switch score{
//case (let s) where s > 90:
//    print("完美")
//case (let x) where x > 80:
//    print("优秀")
//default:
//    print("不合格")
//}


//case还支持坐标
var pos = (30,40)
switch pos{
case (0,0):
    print("在原点")
case (0,_): //y轴不知道在哪里,表示缺省
    print("在y轴上")
case (_, 0):
    print("在x轴上")
default:
    print("在这个位置上")
}

函数

swift 复制代码
import Foundation

//func定义函数
//func hello(){
//    print("这个一个无参无返回值的函数")
//}
//hello();//调用

//func hello1(name:String){
//    print("这个一个有一个参无返回值的函数")
//}
//hello1(name: "zhansan")

//func hello2(name:String, age:Int){
//    print("这个一个多参无返回值的函数")
//}
//hello2(name: "zhangsan", age: 23)

//如果只有一个返回值,可以不写名字,直接写类型
//func hello3() -> (name:String, age:Int){
//    print("这个一个无参有返回值的函数")
//    return ("zhansan", 34)
//}
//var (name, age) = hello3()//用元组进行接收
//print(name, age)


//参数名字也可以写两个,左边的n1 n2是外面调用时用,右边的a b函数体内部用的
//func hello4(n1 a:Int, n2 b:Int) -> Int{
//    return a + b
//}
//let x = hello4(n1: 1, n2: 2)
//print(x)

//在调用时也可以没有任何标签
//func hello4(_ a:Int, _ b:Int) -> Int{
//    return a + b
//}
//let x = hello4(2,3)
//print(x)

//如果参数要传非常多个,比如说实现1+2+3+4+5+6...
//func hello5(_ num:Int...) -> Int{
//    var s = 0
//    for i in num{
//        s += i
//    }
//    return s
//}
//let x = hello5(1,2,3,4,5,6,7,8,9)
//print(x)

//还可以指定参数的值
func hello5(_ a:Int = 10) -> Int{
    return a + 1
}

函数的使用

swift 复制代码
import Foundation

//如果要修改参数的值,并在函数调用后修改的值仍然存在
//要使用 输入输出型参数,在参数定义前加 inout 关键字,且这个值需要是变量而不是常量
func hello(n: inout Int) {
    n += 1
}
var a = 10
hello(n:&a)
//print(a)//11


//函数实现:向左截取n个字符
func excelLeft(s:String, n:Int)->String{
    let s1 = s[s.startIndex...s.index(s.startIndex, offsetBy: n-1)]//[开始位置,开始位置+n]
    return String(s1)
}
let ret = excelLeft(s: "中国人民站起来了!", n: 4)
//print(ret)

//let str2 = "assdfghjjkkl"
//print(str2[str2.startIndex]) //a
//print(str2[str2.index(before:str2.endIndex)])//l
//print(str2[str2.index(str2.endIndex, offsetBy: -2)])//k

枚举

swift 复制代码
import Foundation

//枚举的定义
enum Weekday{ //首字母大写
    case Mon
    case Tue
    case Wed
    case Thu
    case Fri
    case Sat
    case Sun
}
//let a = Weekday.Mon //推断出来其类型是Weekday
//print (a) //Mon
//print(type(of: a)) //Weekday
//
//var b:Weekday = Weekday. Thu
//print(b)


//让枚举遵循 CaseIterable 协议,Swift 会自动为你生成一个静态属性 allCases,它是一个包含所有枚举成员的数组.
enum Direction:CaseIterable{
    case west,east,south,north //在一行上声明
}
//print(Direction.west)
//枚举的遍历
for s in Direction.allCases{
//    print(s)
}

var d = Direction.south
d = .east //对成员进行修改,前面的类型名Direction可以省略

//枚举匹配
//switch d{
//case .east:
//    print("东方")
//case .north:
//    print("北方")
//case .west:
//    print("西方")
//case .south:
//    print("南方")
//}


//有时候只有一个状态含有的信息量太少了,可以在状态后面加其他信息,这些信息叫做关联值
enum PlayerState{
    case idle
    case walk(speed: Int)
    case run(speed: Int)
    case fly(speed:Int, height: Int)
    case die
}
var al = PlayerState.idle
var a2 = PlayerState.walk(speed: 300)
var a3 = PlayerState.fly(speed: 300, height: 800)

//这样在进行匹配时
//switch al {
//case .idle:
//    print("玩家正在待机")
//case .walk(let speed):
//    print("玩家正在以\(speed)速度行走")
//case .run(let speed):
//    print("玩家正在以\(speed)速度奔路")
//case .fly(let speed, let height):
//    print("玩家在\(height)高空以\(speed)速度行")
//case .die:
//    print("玩家已死")
//}


//枚举的原始值
//可以自定义原始值
enum Gender:Int {
    case man = 10
    case women
    case unknow
}
//print(Gender.man)
//print(Gender.man.rawValue) //0+10
//print(Gender.women.rawValue) //1+10
//print(Gender.unknow.rawValue) //2+10

枚举的description属性

swift 复制代码
import Foundation

//实例1
enum Weather {
    case sunny, cloudy, rainy, sonwy, windy
    
    //description是每一种数据类型都有一个属性,这里重新定义了一下
    var description: String{
        switch self {
        case .sunny:
            return"晴天"
        case .cloudy:
            return"多云"
        case .rainy:
            return"雨天"
        case .sonwy:
            return"下雪"
        case .windy:
            return"大风"
        }
    }
}
//print (Weather.sunny.description)


//实例2
enum Shape {
    case retangle(width: Double, height: Double)
    case circle(radius: Double)
    case triangle(sidel: Double, side2: Double, side3: Double)
    
    var description: Double {
        switch self {
        case .circle(let radius):
            return Double.pi * radius * radius
        case .retangle(let width, let height):
            return width * height
        case .triangle(let sidel, let side2, let side3):
            return (sidel * side2 * side3) / (2 * sqrt(sidel * side2 * side3))
        }
    }
}
print(Shape.retangle(width: 100, height: 200).description)

闭包

swift 复制代码
import Foundation

//闭包

//先来一个函数
func hello(name:String) -> Void{
//    print("名字是\(name)")
}
//hello(name: "zhangsan")

//闭包可以理解为匿名函数
//把参数也放在{}里面,用 in 分隔
let ret = {
    (name:String) -> () in
//    print("名字是\(name)")
}
//ret("lisi")


//闭包也可以作为函数参数
//func hello2(action:()->Void){
//    action()//你好
//    print("占三")//占三
//}
//let ret2 = {
//    print("你好")
//}
////hello2(action: ret2)//调用方式1
//hello2 {
//    //调用方式2:可以直接把闭包写进来,这叫做 尾随闭包
//    print("你好")
//}



//函数的参数是另一个函数

//func travel(action: () -> Void) {
//    print("我现在出发")
//    action()
//    print("我已经到了")
//}
//第一种写法:正常
//travel(action: {
//    print("我座火车去郑州")
//})
//第二种写法 这个函数的最后一个参数是闭包参数时,就可以使用这种方法
//travel{
//    print("我座火车去郑州")
//}

//如果函数有一个参数
//func travel(action: (String) -> Void) {
//    print("我现在出发")
//    action("漳州")
//    print("我已经到了")
//}
//travel{
//    (place:String) in
//    print("我坐火车去\(place)")
//}

//如果函数有2个参数
//func travel(action: (String, Int) -> String) {
//    print("我现在出发")
//    print(action("漳州", 200))
//    print("我已经到了")
//}
//travel{
//    (place:String, speed:Int) in
//    return("我坐火车去\(place),以\(speed)的速度")
//}

//一个函数的返回值时一个函数
//travel函数的返回值是一个 string类型无返回值的函数
//func travel() -> (String)->Void{
//    return {(place:String) in
//        print("我想去\(place)")
//    }
//}
//let ret3 = travel() //先调用travel函数,用值接收它的返回值
//ret3("漳州")


func read (book: String) -> () -> () {
    print("我正在读\(book)")
    var counter = 0
    return{
        counter += 1
        print("第\(counter)次读\(book)")
    }
}
let a = read(book: "三国演义")
a()
a()

数组中使用闭包的函数

swift 复制代码
import Foundation

//在数组中使用闭包的函数

let num = [1,2,3,4,5,6,7,8,9,10]

//map函数的作用:产生新的数组,每一个元素要经过map的加工
//写法1
//let n1 = num.map({(n:Int) in
//    return n * n;
//})

//写法2
let n1 = num.map({
    $0 * $0
})
//print(n1)


//filter:产生新数组,每一个元素要经过filter的判断过滤,true返回,false就过滤掉
let n2 = num.filter({
    $0 > 5 //返回数组中大于5的数
})
//print(n2)


//reduce的两个参数:初始的结果,遍历过程中的每一次的结果
//reduce(<#T##initialResult: Result##Result#>, <#T##nextPartialResult: (Result, Int) throws -> Result##(Result, Int) throws -> Result##(_ partialResult: Result, Int) throws -> Result#>)
let n3 = num.reduce(0, {
    $0 + $1
})
//第一次运行时,$0就是初始结果0,$1就是1,他们的和1就放在初始结果的位置上,
//第一次运行时,$0就是初始结果1,$1就是2,他们的和3就放在初始结果的位置上
//....
//以此类推,达到累加的效果
print(n3)

struct初识

swift 复制代码
//
//  main.swift
//  sf28
//
//  Created by test on 2026/6/1.
//

import Foundation

//有一张空的学生成绩表

//Swift 的结构体中,属性必须满足以下条件之一:
//1.声明时直接赋值默认值(编译器可以自动推断类型)
//2.显式声明类型(即使没有默认值也可以)

struct Student{
    var name = ""
    var age:Int = 0
    var chinese:Int = 0
    var math:Int = 0
    var total:Int = 0
    
    mutating func cacl(){
        self.total = self.chinese + self.math
    
//  结构体(struct)是值类型,默认情况下,它的方法不能修改自身属性,必须用 mutating 标记方法。
//    你写的 func cac1() 是一个普通结构体方法,默认情况下,结构体的 self 是不可变的(immutable),你在方法里试图修改self.total,但普通方法不允许修改结构体自身的属性,所以编译器直接报错了
//    mutating 的作用就是告诉编译器:这个方法会修改结构体自身的属性,让 self 变成可变的。
    }
}

//创建结构体实例,必须用结构体名 Student(...),不能用变量名 s
//var s:Student;

//var s1 = Student(name:"zhangsan", age:12, chinese:89, math:90)
//s1.cacl()
//print(s1)

var s2 = Student()

//如果是class,成员变量必须初始化

struct和class的不同点:

属性

1、定义:属性用来描述类,结构体或者枚举里面的值。

2、分类:

存储属性

计算属性

类型属性

存储属性:

  • 存储类或者结构体实例里的一个常量或者变
  • 类似Object-C的成员变量
  • 可以指定默认值,可修改

计算属性

  • 类、结构体和枚举间接获取和设置其他属性
    的值。
  • 类似Object-C的getter和setter器。
swift 复制代码
import Foundation

//存储属性
struct FixedLengthRange {
    var firstValue: Int
    let length: Int
}
var range = FixedLengthRange(firstValue: 10, length: 5)
range.firstValue = 20

//延迟存储属性
//lazy stored pro
//lazy属性的初始化闭包,只会在第一次访问这个属性时执行,之后再访问会直接用已经初始化好的值。
class ClassWithLazyProperty {
    lazy var players: [String] = {
        print("lazy players init")
        var tempPlayers = ["Bob","kate"]
        tempPlayers.append("allen")
        return tempPlayers
    }()
}
//var a = ClassWithLazyProperty()
//a.players
//a.players.append ("king")
//a.players


//计算属性
struct Time {
    var seconds = 0.0
    
    //设计计算属性的读取器和设置器
    var minutes: Double {
        get{
            return (seconds/60)
        }
        set {
            self.seconds = newValue * 60
        }
    }
    var hours: Double {
        get {
            return (seconds/3600)
        }
        set (newHours) {
            self.seconds = newHours*3600
        }
    }
    //设计只读
    //如果只有一个只读属性,写法上可以把get{}省略
    var day:Double{
            get{
                return seconds / (3600*24)
            }
        }
}
//var time = Time(seconds: 10)
//print(time.minutes)
//print(time.hours)
//
//time.minutes = 60
//print(time.seconds)
//
//time.hours = 2
//print(time.seconds)
//print(time.minutes)


//属性观察器
//willSet:在属性即将被赋值前触发,可以拿到即将被设置的新值 newValue
//didSet:在属性赋值完成后触发,可以拿到旧值 oldValue 和更新后的新值
class StepCounter {
    var totalSteps = 0 {
        willSet {
            print("willset newvalue \(newValue)")
        }
        didSet {
            print("oldvalue is \(oldValue), new value is \(totalSteps)")
        }
    }
}

let stepCounter = StepCounter()
//stepCounter.totalSteps = 10

//关键点:
//1、属性观察器只会在属性被修改时触发
//初始化时的赋值不会触发 willSet 和 didSet
//比如 var totalSteps = 0 这句,不会执行观察器里的代码
//只有后续给 totalSteps 赋值(比如 = 10)才会触发
//2、newValue 和 oldValue 是 Swift 提供的隐式参数
//willSet 里默认可以用 newValue 拿到新值
//didSet 里默认可以用 oldValue 拿到旧值
//也可以自己命名,比如 willSet(newVal)、didSet(oldVal)
//3、可以同时用 willSet 和 didSet,也可以只写其中一个
//比如只监听修改后的变化,只写 didSet 也完全可以。


//实例属性和类型属性(有static修饰)
//类型属性:不管定义了多少份实例,类型属性只有一份
struct SomeStructer {
    static var valuel = "some value"
    static var computeValue: Int {
        return 1
    }
}

class SomeClass {
    static var valuel = "some value"
    static var seconds = 0.0
    static var computeValue: Double {
        get {
            return seconds/60
        }
        set {
            seconds = newValue*60
        }
    }
}
//类型属性要用 结构体名/类名.成员名 访问
var testStruct = SomeStructer()
SomeStructer.valuel = "value2"
SomeStructer.computeValue

SomeClass.seconds
SomeClass.computeValue = 60

类的继承和重写

swift 复制代码
import Foundation

//继承
class Person {
    var name : String = ""
    var gender : String = ""
    var age: Int = 0
    final func sleep() {
        print("\(name) is sleeping")
    }
    func eat(food:String) {
        print("\(name) is eating \(food)")
    }
}

class Student: Person {
    var shcoolName: String = "maizi_online"
    
    override func eat (food: String) {
        print("\(name) is eating \(food) at \(shcoolName)")
    }
}

var person = Person ()
var student = Student()

//student.age = 20
//student.gender = "male"
//student.name = "allen"
//student.eat(food:"rice")
//student.sleep()
//print(student.shcoolName)


//重写
//子类可以为继承来的属性和方法提供自己的实现
//若要重写,必须要在前面加override关键字

//重写的规则:
//必须加 override
//签名必须一致:方法名、参数个数/类型、返回值必须和父类完全一样。
//不能重写 private/final:
//     private:子类看不见,不能重写。
//     final:禁止重写(你之前代码里的 final func sleep() 就不能被重写)。
//访问权限不能更低:父类是 public,子类不能写成 internal 或 private。
//类才可以继承:结构体、枚举不能继承,也不能重写。

构造和析构

swift 复制代码
import Foundation

//构造规则
//1、指定构造器 vs 便利构造器
//指定构造器:init(...),负责初始化所有属性,必须调用父类的指定构造器。
//便利构造器:convenience init(...),必须调用同一个类里的其他构造器(最终调用指定构造器)。
//2、子类构造器的执行顺序
//先初始化子类自己的所有存储属性(给它们赋值)。
//调用父类的指定构造器,初始化父类的属性。
//才能访问和修改父类的属性,或者调用父类的方法。
//3、构造器的继承规则
//如果子类没有自定义任何构造器,会自动继承父类的所有构造器。
//一旦子类自定义了构造器,就不再自动继承父类的构造器,必须手动调用 super.init

//析构规则
//类才有结构体和枚举没有,最多一个,无参无返回无括号
//ARC 归零自动调,绝对不能手动调
//继承:子先析构,父自动收尾
//只做轻量清理,别写复杂逻辑

//类的构造
class Person {
    var name : String
    var gender : String
    var age: Int = 0
    final var idStr:String
    
    //自定义无参构造
    //    init(){
    //        self.name = ""
    //        self.gender = ""
    //        self.age = 0
    //        self.idStr = ""
    //    }
    
    //自定义有参构造+其余缺省
    //    init(name:String){
    //        self.name = name
    //        self.gender = ""
    //        self.age = 0
    //        self.idStr = ""
    //    }
    
    //类的遍历构造器
    init(name:String, age:Int){
        self.name = name
        self.gender = ""
        self.age = age
        self.idStr = ""
    }
    convenience init(name:String){
        self.init(name:name, age:0)
    }
    
    //析构函数
    //固定名称deinit,没有带参数
    deinit{
        print("Person class deint")
    }
}

//调用默认构造(编译器自动生成),我们没有定义自己的构造,并且成员变量已初始化
//var p = Person()
//var p1 = Person(name: "zhangsan")

class Student: Person {
    var shcoolName: String = "maizi_online"
    
    //自定义显式构造器
    init(){
        super.init(name: "wabgfwu", age: 45)
    }
    
    //析构函数
    deinit{
        print("Student class deint")
    }
}

func test(){
    let s = Student()
    print(s.age)
}
test()

//子类继承了父类的构造器
var s = Student()//调用默认构造,成员变量已初始化

//当子类自定义构造器后,将不在继承父类的显式构造器和遍历构造器
//var s1 = Student(name: "zhansan")
//var s2 = Student(name: "lisi", age: 23)


//结构体的构造
//struct Size{
//    var height:Double
//    var length:Double
//}
//
//var s = Size(height: 10.0, length: 12.3)

//结构体的构造器代理
struct Size{
    var height:Double
    var length:Double
    
    init(height: Double, length: Double) {
        self.height = height
        self.length = length
    }
    init(height:Double){
        self.init(height: height, length: 0)
    }
}
//var s1 = Size(height: 12.6)

可选链

swift 复制代码
import Foundation

//可选链
//可选链是一种可以请求和调用属性、方法及下标脚本的过程,它的可选性体现于请求或调用的目标当前可能为空。
//通过在想调用的属性、方法、或下标脚本的可选值后面+?,可以定义一个可选链。


//强制解析和可选链的不同
class Residence{
    var numberOfRoom = 1
}

class Person{
    var age = 30
    var residence:Residence? //定义可选类型
    
    //可选方法,返回值是可选值
    func buildHome() -> Residence? {
        return residence
    }
    
    subscript(name:String)->Residence?{
        return residence
    }
}

var p:Person?

//如果我们没有给p进行构造,p默认是nil,此时强制解析会报错,但可选链不会报错
//var res1 = p!.age //使用强制解析访问
//print(type(of: res1)) //Int

var res2 = p?.age //使用可选链访问
//print(type(of: res2)) //Optional<Int>


//可选方法的调用
var p1:Person? = Person()
p1?.residence = Residence()
//print(p1?.buildHome()?.numberOfRoom)//多层可选调用

//p1?["bob"]?.numberOfRoom

//可选链调用下标
var d:[String:Person] = [:]
//print(d["Bob"]?.residence?.numberOfRoom)

//用 if let 安全解析:
if let num = p1?["bob"]?.numberOfRoom{
    print("\(num) of room")
}

类型转换和嵌套类型

swift 复制代码
import Foundation

class Media {
    //类中嵌套枚举
    enum MediaType: Int {
        case media
        case song
        case
        movie
    }
    var mediaType: MediaType = .media
    
    var name: String = ""
    init (name: String) {
        self.name = name
    }
}

class Song: Media {
}

class Movie: Media {
}

let song = Song (name: "Fireproof")
let movie = Movie(name: "Shrek")
let media = Media(name: "King Kong")

//print(type(of: media.mediaType))//MediaType

let a = [song, movie, media]
//print(type(of: a)) //Array<Media>

//类型检查
//print(song is Media) //检查 song是否属于Media类
//print(movie is Media)


//向下转型 as - as? as!
for item in a{
    if let movie = item as? Movie{
//        print("it is a movie with \(movie.name)")
    }else if let song = item as? Song{
//        print("it is a song with \(song.name)")
    }
}
//把Media向下转成Movie类型
let mediaFromMovie:Media = Movie(name: "zhangsan")
//print(type(of: mediaFromMovie)) //Movie


//Any和AnyObject的类型转换
//Swift 为不确定的类型提供的两种特殊类型的别名
//AnyObject可以表示任何class类型的实例
//Any可以表示任何类型,甚至方法
class Person {
    var name = ""
}

var person = Person()
let someObjects: [AnyObject] = [song, movie, media, person]
//print(type(of: someObjects)) //Array<AnyObject>

for item in someObjects {
    if let movie = item as? Movie {
//        print("it is a movie with name \(movie.name)")
    }
    else if let song = item as? Song {
//        print("it is a song with name \(song.name) ")
    }
}

let d = 0.9
var someArrays: [Any] = [song, movie, media, d]

for item in someArrays {
    if let movie = item as? Movie {
//        print("it is a movie with name \(movie.name)")
    }
    else if let song = item as? Song {
//        print("it is a song with name \(song.name) ")
    }
}

其他语法

1、URL类型

2、guard let语法

3、Swift 并发写法

swift 复制代码
Task { @MainActor [weak self] in
    guard let self else { return }
    // ... 后续代码
}

Task { ... }

  • Swift 并发中创建一个新任务的方式,它会把闭包内的代码放到并发线程池里执行。
  • 你这段代码里,是用来把原本在后台线程调用的 photoLibraryDidChange 回调,切回主线程处理 UI。

@MainActor

  • 是 Swift 的全局 actor,作用是:强制把闭包内的代码运行在主线程上。
  • 因为 photoLibraryDidChange 回调是在后台线程触发的,而更新 UI 必须在主线程,所以加上 @MainActor 就可以保证后续所有代码都在主线程执行。

weak self

  • 闭包的捕获列表,表示在闭包内对 self 是弱引用。
  • 目的是防止循环引用(Task 持有控制器,控制器又持有 Task),导致控制器无法被释放,造成内存泄漏。

in

  • 闭包的语法标记,weak self 是捕获列表,in 后面就是闭包的代码体。

guard let self else { return }

  • 安全解包 self,因为前面用了 weak self,所以 self 变成了可选型 Self?。
  • 如果控制器已经被释放(self 为 nil),就直接 return,避免后续代码崩溃。

4、extension

extension 是 Swift 里的一个核心语法,作用是给已有的类 / 结构体 / 枚举 / 协议,"额外添加功能",又不改原来的代码。

1.它能干啥?

用 extension 可以给已有的类型添加:

新的方法

新的计算属性

遵守新的协议并实现协议方法

嵌套类型

2.但有几个限制:

不能加存储属性(不能直接给类加新的 var x = 0)

不能重写原来已有的方法(比如不能覆盖系统自带的 UIView 方法)。

结合自定义相册代码来看,使用 extension(按职责分开):

swift 复制代码
extension ViewController: UICollectionViewDataSource {
    // ... 实现数据源方法
}

extension ViewController: UICollectionViewDelegate {
    // ... 实现代理方法
}

extension ViewController: WaterfallLayoutDelegate {
    // ... 实现瀑布流高度方法
}

对比不使用 extension(代码堆在一起):

swift 复制代码
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
    func viewDidLoad() { ... }

    // 一堆数据源方法
    func collectionView(_:numberOfItemsInSection:) -> Int { ... }
    func collectionView(_:cellForItemAt:) -> UICollectionViewCell { ... }

    // 一堆代理方法
    func collectionView(_:didSelectItemAt:) { ... }

    // 瀑布流方法
    func heightForItemAt(...) -> CGFloat { ... }
}