swift所有的语法
一) 基本数据类型 :
if let temp1 = obj1, let temp2 = obj2, temp1 < temp2 {
// 当全部不为 nil 且满足子句 temp1 < temp2
print(temp1, temp2) // 1 2
} else {
print("obj1 or obj2 may be nil")
}
// 在数值前可加 0 进行位数填充,可加入下划线,增加可读性
var number1 = 001.234 // 1.234
var number2 = 1_234 // 1234
// 打印多个值使用逗号分隔
print(number1, number2) // 1.234 1234
二) Swift 字符串类型及常用方法
“let greeting = "Hello, world!"
let index = greeting.firstIndex(of: ",") ?? greeting.endIndex
let beginning = greeting[..<index]
// beginning 的值为 "Hello"
// 把结果转化为 String 以便长期存储。
let newString = String(beginning)”
字符串截取:
let index1:String.Index = stre.index(before: stre.endIndex)
let index2:String.Index = stre.index(stre.endIndex, offsetBy: -2)
let str22 = stre[index2...index1]
获取某个字符:
var afterChar = indexStr[indexStr.index(after: startIndex)] // e
字符串的常用方法 blog.csdn.net/java_androi…
range的范围 startIndex...indexStr.index(startIndex, offsetBy: 13)
// 字符串判空
var emptyStr = ""
if emptyStr.isEmpty {
print("string is empty")
}
if emptyStr.count == 0 {
print("string count is 0")
}
// 字符串判大小,会逐个比较字符大小
let str1 = "100a", str2 = "101a"
if (str1 < str2) {
print("str1 < str2")
}
// 字符串判相等,会比较所有字符的位置都相等,才为相等的字符串
if (str1 == str2) {
print("str1 < str2")
}
// 使用下标访问字符
var indexStr = "Hello, William"
// 获取起始下标
var startIndex: String.Index = indexStr.startIndex
var endIndex: String.Index = indexStr.endIndex
// 获取某个下标后一个下标对应的字符
var afterChar = indexStr[indexStr.index(after: startIndex)] // e
// 获取某个下标前一个下标对应的字符
var beforeChar = indexStr[indexStr.index(before: endIndex)] // m
// ... 运算符指定范围,从 startIndex 向后移动4位截取子串
var subStr = indexStr[startIndex...indexStr.index(startIndex, offsetBy: 4)] // hello
// 从endIndex 向前移动7位截取子串
var subStr2 = indexStr[indexStr.index(endIndex, offsetBy: -7)..<endIndex] // William
// 获取范围
var range = indexStr.range(of: "Hello")
// 追加字符串
indexStr.append(Character("."))
indexStr.append(" append string") // Hello, William. append string
// 插入单个字符到指定位置 Hello, William.# append string
indexStr.insert("#", at: indexStr.index(startIndex, offsetBy: 15))
// 插入一组字符 Hello, William.-#-# append string
indexStr.insert(contentsOf: ["-", "#", "-"], at: indexStr.index(startIndex, offsetBy: 15))
// 替换指定范围的字符串 How are you.-#-# append string
indexStr.replaceSubrange(startIndex...indexStr.index(startIndex, offsetBy: 13), with: "How are you")
// 删除指定位置的单个字符 How are you.-#-# append strin
indexStr.remove(at: indexStr.index(before: indexStr.endIndex))
// 删除指定范围 -#-# append strin
indexStr.removeSubrange(indexStr.startIndex...indexStr.index(indexStr.startIndex, offsetBy: 11))
// 删除所有字符 ""
indexStr.removeAll()
// 转换大小写
var uppercase = "hello, swift".uppercased() // HELLO, SWIFT
var lowercase = "HELLO, SWIFT".lowercased() // hello, swift
// 检查前后缀
var hasPrefix = uppercase.hasPrefix("he") // false
var hasSuffix = lowercase.hasSuffix("ft") // true
三) 数组 及常用方法
- 创建数组
// 创建整型数组
var array1: [Int] = [] // []
var arrya2: Array<Int> = [1, 2, 3] // [1, 2, 3]
var arryaInt = [1, 2, 3] // [1, 2, 3]
var array3 = Array(arrayLiteral: 1, 2, 3) // [1, 2, 3]
- 快捷创建重复元素的数组
var array4 = Array(repeating: "swift", count: 3) // ["swift", "swift", "swift"]
var array5 = Array(repeating: 1001, count: 3) // [1001, 1001, 1001]
- 数组相加
// 2个相同类型的数组相加
var array6 = [1, 2, 3] + [4, 5, 6] // [1, 2, 3, 4, 5, 6]
- 常用方法
// 当数组声明为可变时,才能使用增,删,改等方法,常量数组不能进行修改相关操作
var array = [1, 2, 3, 4, 5, 6, 7, 8]
print(array.count) // 8
// 判断数组是空数组
if array.isEmpty {
print("array is empty")
} else {
print("array is not empty")
}
// 通过下标访问元素
var ele = array[1] // 2
// 截取新数组
var subArray = array[1...2] // [2, 3]
// 获取第一个元素
var firstEle = array.first // 1
// 获取最后一个元素
var lastEle = array.last // 8
// 修改下标对应的元素
array[1] = 22
array // [1, 22, 3, 4, 5, 6, 7, 8]
// 修改指定范围的元素
array[0...2] = [1, 2, 3] // [1, 2, 3]
// 追加单个元素
array.append(9) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
// 追加一组元素
array.append(contentsOf: [10, 11, 12]) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
// 在指定位置插入单个元素
array.insert(0, at: 0) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
// 在指定位置插入一组元素
array.insert(contentsOf: [-3, -2, -1], at: 0) // [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
// 移除指定元素
array.remove(at: 1) // -2
// 移除一组元素
array.removeSubrange(0...2) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
// 移除首个元素
array.removeFirst() // 1
// 移除末尾元素
array.removeLast() // 12
// 移除前几个元素
array.removeFirst(3) // [5, 6, 7, 8, 9, 10, 11]
// 移除后几个元素
array.removeLast(3) // [5, 6, 7, 8]
// 替换指定范围的元素
array.replaceSubrange(0...3, with: [1, 2, 3, 4]) // [1, 2, 3, 4]
// 判断包含指定元素
if array.contains(3) {
print("array contains 3")
}
// 移除所有元素
array.removeAll() // []
var sortArr = [2, 1, 3, -1]
// 从小到大排序
sortArr.sorted(by: <) // [-1, 1, 2, 3]
// 从大到小排序
sortArr.sorted(by: >) // [3, 2, 1, -1]
// 获取数组最大值
sortArr.min() // -1
// 获取数组最小值
sortArr.max() // 3
定义二维数组 matrix:[[Int]], matrix[row][column]
var visited = Array(repeating: Array(repeating: false, count: matrix[0].count), count: matrix.count)
matrix[row][col] == path[path.index(path.startIndex, offsetBy: pathIndex)] && !visited[row][col]) {
数组的常用方法
创建 var array4 = Array(repeating: "swift", count: 3) // ["swift", "swift", "swift"]
创建
var array1: [Int] = [] // []
var arrya2: Array<Int> = [1, 2, 3] // [1, 2, 3]
var arryaInt = [1, 2, 3] // [1, 2, 3]
数组相加 +
数组为空isEmpty
数组截取 var subArray = array[1...2] // [2, 3]
数组的元素:
// 获取第一个元素
var firstEle = array.first // 1
// 获取最后一个元素
var lastEle = array.last // 8
常用方法
// 当数组声明为可变时,才能使用增,删,改等方法,常量数组不能进行修改相关操作
var array = [1, 2, 3, 4, 5, 6, 7, 8]
print(array.count) // 8
// 判断数组是空数组
if array.isEmpty {
print("array is empty")
} else {
print("array is not empty")
}
// 通过下标访问元素
var ele = array[1] // 2
// 截取新数组
var subArray = array[1...2] // [2, 3]
// 获取第一个元素
var firstEle = array.first // 1
// 获取最后一个元素
var lastEle = array.last // 8
// 修改下标对应的元素
array[1] = 22
array // [1, 22, 3, 4, 5, 6, 7, 8]
// 修改指定范围的元素
array[0...2] = [1, 2, 3] // [1, 2, 3]
// 追加单个元素
array.append(9) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
// 追加一组元素
array.append(contentsOf: [10, 11, 12]) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
// 在指定位置插入单个元素
array.insert(0, at: 0) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
// 在指定位置插入一组元素
array.insert(contentsOf: [-3, -2, -1], at: 0) // [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
// 移除指定元素
array.remove(at: 1) // -2
// 移除一组元素
array.removeSubrange(0...2) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
// 移除首个元素
array.removeFirst() // 1
// 移除末尾元素
array.removeLast() // 12
// 移除前几个元素
array.removeFirst(3) // [5, 6, 7, 8, 9, 10, 11]
// 移除后几个元素
array.removeLast(3) // [5, 6, 7, 8]
// 替换指定范围的元素
array.replaceSubrange(0...3, with: [1, 2, 3, 4]) // [1, 2, 3, 4]
// 判断包含指定元素
if array.contains(3) {
print("array contains 3")
}
// 移除所有元素
array.removeAll() // []
var sortArr = [2, 1, 3, -1]
// 从小到大排序
sortArr.sorted(by: <) // [-1, 1, 2, 3]
// 从大到小排序
sortArr.sorted(by: >) // [3, 2, 1, -1]
// 获取数组最大值
sortArr.min() // -1
// 获取数组最小值
sortArr.max() // 3
数组的遍历
let arr = [11, 22, 33]
for item in arr {
print(item)
}
// 打印数组的下标及对应元素
for item in arr.enumerated() {
print(item) // (offset: 0, element: 11) (offset: 1, element: 22) (offset: 2, element: 33)
}
// 下标遍历
for index in arr.indices {
print(arr[index])
}
四 Swift 集合 Set 及常用方法
- 创建Set集合
// 创建Set
var set: Set<Int> = [1, 2, 3]
var set2 = Set(arrayLiteral: 1, 2, 3)
- 获取元素
// set 获取最小值
set.min()
// 获取第一个元素,顺序不定
set[set.startIndex]
set.first
// 通过下标获取元素,只能向后移动,不能向前
// 获取第二个元素
set[set.index(after: set.startIndex)]
// 获取某个下标后几个元素
set[set.index(set.startIndex, offsetBy: 2)]
- 常用方法
// 获取元素个数
set.count
// 判断空集合
if set.isEmpty {
print("set is empty")
}
// 判断集合是否包含某个元素
if (set.contains(3)) {
print("set contains 3")
}
// 插入
set.insert(0)
// 移除
set.remove(2)
set.removeFirst()
// 移除指定位置的元素,需要用 ! 拆包,拿到的是 Optional 类型,如果移除不存在的元素,EXC_BAD_INSTRUCTION
set.remove(at: set.firstIndex(of: 1)!)
set.removeAll()
var setStr1: Set<String> = ["1", "2", "3", "4"]
var setStr2: Set<String> = ["1", "2", "5", "6"]
// Set 取交集
setStr1.intersection(setStr2) // {"2", "1"}
// Set 取交集的补集
setStr1.symmetricDifference(setStr2) // {"4", "5", "3", "6"}
// Set 取并集
setStr1.union(setStr2) // {"2", "3", "1", "4", "6", "5"}
// Set 取相对补集(差集),A.subtract(B),即取元素属于 A,但不属于 B 的元素集合
setStr1.subtract(setStr2) // {"3", "4"}
var eqSet1: Set<Int> = [1, 2, 3]
var eqSet2: Set<Int> = [3, 1, 2]
// 判断 Set 集合相等
if eqSet1 == eqSet2 {
print("集合中所有元素相等时,两个集合才相等,与元素的顺序无关")
}
let set3: Set = [0, 1]
let set4: Set = [0, 1, 2]
// 判断子集
set3.isSubset(of: set4) // set3 是 set4 的子集,true
set3.isStrictSubset(of: set4) // set3 是 set4 的真子集,true
// 判断超集
set4.isSuperset(of: set3) // set4 是 set3 的超集,true
set4.isStrictSuperset(of: set3) // set4 是 set3 的真超集,true
- Set 遍历
// 遍历元素
for ele in set4 {
print(ele)
}
// 遍历集合的枚举
for ele in set4.enumerated() {
print(ele)
}
// 下标遍历
for index in set4.indices {
print(set4[index])
}
// 从小到大排序后再遍历
for ele in set4.sorted(by: <) {
print(ele)
}
四) Swift 字典 Dictionary 集合类型
##1) 创建空字典
var emptyDict1: [Int : String] = [:]
var emptyDict2: Dictionary<Int, String> = Dictionary()
// 指定键值类型
var dict: [Int : String] = [0: "Zero", 1: "One", 2: "Two"]
var dict2: Dictionary<Int, String> = Dictionary(dictionaryLiteral: (1, "One"), (2, "Two"))
// 自动推断键值类型
var dictAuto = [0: "Zero", 1: "One", 2: "Two"]
var dic1=[1:1,2:12,3:32,4:16,5:15]
var dic2:Dictionary<String,String>=[:]
var dic3=Dictionary<String,String>()
var dic4=[String : String]()
- 获取元素
// 获取元素个数
dict.count // 3
// 判断字典为空
dict.isEmpty // false
// 获取键对应的值
dict[1] // One
- 更新键值对
// 修改键对应的值
dict[0] = "000" // 000
// 如果键存在,就更新,否则就新增键值对
dict[-1] = "-1" // -1
// 更新键对应的值,如果键不存在,返回 nil
if let lastValue = dict.updateValue("new one", forKey: 1) {
print("the last value is \(lastValue)") // the last value is One
}
// 移除键值对
dict.removeValue(forKey: -1) // -1
// 移除所有键值对
//dict.removeAll()
- 遍历字典
// dict [1: "new one", 2: "Two", 0: "000"]
// 遍历字典的键
for ele in dict.keys {
print(ele)
}
// 遍历字典的值
for ele in dict.values {
print(ele)
}
// 元组遍历,直接获取键值对
for (key, val) in dict {
print("\(key):\(val)")
}
// 对 key 进行从小到大排序后遍历,并对值进行拆包
for ele in dict.keys.sorted(by: <) {
print(dict[ele]!)
}
//1 读取字典元素
var test1Dic=["key1":"你好","key2":"Swift","key3":"正在学习","key4":"字典","key5":"取值",]
var test1Str=test1Dic["key2"]
println("\(test1Str)")
//此处取字典中未定义的键 不会报错,取出来的值为nil
var test1Str2=test1Dic["key"]
println("\(test1Str2)")
//2 获取字典元素的个数
println(test1Dic.count)
//3 增加字典的元素
test1Dic["key"]="test"
println(test1Dic)
//4 删除字典中的元素
test1Dic.removeValueForKey("key1")
println(test1Dic)
//5 修改字典中的元素
// 5.1 直接修改
test1Dic["key"]="testkey"
// 5.2 使用 updateValue
var oldStr=test1Dic.updateValue("testkeytest", forKey: "key")
println(oldStr)
println(test1Dic)
//6 遍历
//6.1遍历所有的键值对
for (key,value) in test1Dic{
println("key:\(key) value:\(value)")
}
//6.2 遍历所有的键
for test6Str in test1Dic.keys{
println(test6Str)
}
//6.2 遍历所有的值
for test6Str2 in test1Dic.values{
println(test6Str2)
}
//7 字典转数组
//7.1 将所有的键转为数组
var test7Keys=Array(test1Dic.keys)
println(test7Keys)
//7.1 将所有的值转为数组
var test7Values=Array(test1Dic.values)
println(test7Values)
swift 字典常用方法
https://blog.csdn.net/qq_32582087/article/details/49737755
https://wenku.baidu.com/view/2eef2223874769eae009581b6bd97f192279bf3a.html
五) 集合 set 常用方法
** 集合的常用**
https://wenku.baidu.com/view/92af6034f9d6195f312b3169a45177232f60e4d0.html
import UIKit
var greeting = "Hello, playground"
// 集合类型:集合 Set
// 不关注顺序,但不可以重复
// 创建Set
var set: Set<Int> = [1, 2, 3]
var set2 = Set(arrayLiteral: 1, 2, 3)
// set 获取最大值
set.max()
// set 获取最小值
set.min()
// 获取第一个元素,顺序不定
set[set.startIndex]
set.first
// 通过下标获取元素,只能向后移动,不能向前
// 获取第二个元素
set[set.index(after: set.startIndex)]
// 获取某个下标后几个元素
set[set.index(set.startIndex, offsetBy: 2)]
// 获取元素个数
set.count
// 判断空集合
if set.isEmpty {
print("set is empty")
}
// 判断集合是否包含某个元素
if (set.contains(3)) {
print("set contains 3")
}
// 插入
set.insert(0)
// 移除
set.remove(2)
set.removeFirst()
// 移除指定位置的元素,需要用 ! 拆包,拿到的是 Optional 类型,如果移除不存在的元素,EXC_BAD_INSTRUCTION
set.remove(at: set.firstIndex(of: 1)!)
set.removeAll()
var setStr1: Set<String> = ["1", "2", "3", "4"]
var setStr2: Set<String> = ["1", "2", "5", "6"]
// Set 取交集
setStr1.intersection(setStr2) // {"2", "1"}
// Set 取交集的补集
setStr1.symmetricDifference(setStr2) // {"4", "5", "3", "6"}
// Set 取并集
setStr1.union(setStr2) // {"2", "3", "1", "4", "6", "5"}
// Set 取相对补集(差集),A.subtract(B),即取元素属于 A,但不属于 B 的元素集合
setStr1.subtract(setStr2) // {"3", "4"}
var eqSet1: Set<Int> = [1, 2, 3]
var eqSet2: Set<Int> = [3, 1, 2]
// 判断 Set 集合相等
if eqSet1 == eqSet2 {
print("集合中所有元素相等时,两个集合才相等,与元素的顺序无关")
}
let set3: Set = [0, 1]
let set4: Set = [0, 1, 2]
// 判断子集
set3.isSubset(of: set4) // set3 是 set4 的子集,true
set3.isStrictSubset(of: set4) // set3 是 set4 的真子集,true
// 判断超集
set4.isSuperset(of: set3) // set4 是 set3 的超集,true
set4.isStrictSuperset(of: set3) // set4 是 set3 的真超集,true
// 遍历元素
for ele in set4 {
print(ele)
}
// 遍历集合的枚举
for ele in set4.enumerated() {
print(ele)
}
// 下标遍历
for index in set4.indices {
print(set4[index])
}
// 从小到大排序后再遍历
for ele in set4.sorted(by: <) {
print(ele)
}
六) Swift 运算符、循环、流程控制 for-in, while, if-else, switch-case, guard-else
- 运算符:三目,空合并,区间运算符
// 元组比较大小。需要元素个数一致,对应的位置的元素类型相同,每一个元素都必须支持比较运算操作。
// 从第一个元素开始比较,如果没有比较出结果,那么继续依次比较,直到比出结果为止。
var a = (1, 2, "3")
var b = (1, 2, "4")
var c = a < b // true
// 条件判断
if a > b {
print("a > b")
} else {
print("a < b")
}
// 三目运算,同 java
print(a > b ? "a > b" : "a < b") // a < b
var str: String? = "text"
var result: String = str != nil ? str! : ""
// 空合并运算符,如果 str 为 nil,则赋值空串,同 kotlin 的 Elvis 运算符 ?:
result = str ?? ""
// 区间运算符,[1, 5],范围是 >=1, <=5,类似于 Kotlin 的区间 1..5
var rang1 = 1...5
// 区间运算符,[1, 5),范围是 >=1, <5
var rang2 = 1..<5
// 判断是否在某个区间范围内
print(rang1 ~= 2) // true
- 循环:for-in, while, repeat-while
// 区间运算符用于循环
for index in rang1 {
print(index)
}
// 中断循环 break
for index in 0...2 {
if index == 1 {
break
}
print(index) // 0
}
// 跳过当前循环 continue
for index in 0...2 {
if index == 1 {
continue
}
print(index) // 0 2
}
// 中断外层循环 break,类似于 Kotlin 的限定符
OutterLabel:for outterIndex in 0...2 {
for index in 0...1 {
if outterIndex == 1 {
break OutterLabel
}
print(index) // 0 1
}
}
// while 循环
var i = 0
while i < 3 {
print(i) // 0, 1, 2
i += 1
}
// 即 do-while,先执行一次循环,再判断条件
var k = 0
repeat {
print(k) // 0, 1, 2
k += 1
} while k < 3
- 流程控制:if-else, switch-case
// 流程控制 if-else
let number = 18
if number < 15 {
print("number < 15")
} else if number >= 16 && number <= 20 {
print("number >= 16 && number <= 20")
} else {
print("number > 20")
}
// 流程控制 switch-case
var caseStr = "a"
switch caseStr {
case "a":
print("value is a")
case "b":
print("value is b")
default:
print("default value")
}
// switch 子句多条件匹配
switch caseStr {
case "a","b","c":
print("match success")
default:
print("default value")
}
// switch 子句区间范围匹配
let age = 18
switch age {
case 16..<18:
print("match age 16...18")
case 18...20:
print("match age 18..<20")
default:
print("default value")
}
// switch 元组匹配
let intTuple = (1, 2)
switch intTuple {
case (1, 2):
print("match success 1, 2")
fallthrough // 继续执行后续 case 匹配,不跳出 switch
case (2, 2):
print("match success 2, 2")
fallthrough
case (_, 2):
// 选择性匹配,第一个匿名不关注,只有第二个能匹配,就算匹配成功
print("match success _,2")
fallthrough
case (0...2, 0...2):
// 匹配元组元素的范围
print("match range success")
case (let a, 1):
print("捕获元素: \(a)")
case let(a, b) where a < b:
// 同 (let a, let b),增加 where 字句判断
print("捕获元组: \(a),\(b)")
fallthrough
default:
print("default")
}
- guard-else 守护判断
// 调用 method
method()
func method() {
// 守护语句,当 guard 后面的条件成立时,才继续执行,替换之前的 if-return
guard number > 20 else {
return
}
print("continue execute")
}
七) Swift 函数与闭包
- 创建函数
// 创建函数,无参,无返回值,同 func func1() -> Void
func func1() {
print("no params func")
}
func1()
// 创建函数,带参,带返回类型
func func2(param: Int) -> Bool {
return param > 60
}
func2(param: 80)
// 创建函数,带多个参数,返回类型为元组
func func3(param1: String, param2: Int) -> (result1: String, result2: Int) {
return (param1 + "11", param2 + 20)
}
let tuple = func3(param1: "param", param2: 60)
if tuple.result1.starts(with: "param") {
print(tuple.result2)
}
// 创建函数,带参,返回类型为 Optional
func func4(param: Int) -> Int? {
guard param > 2 else {
return nil
}
return param + 2
}
if let result = func4(param: 3) {
print(result)
}
- 函数内外参数命名
// 函数参数指定外部名称
func outerNameFunc(name1 param1: Int, name2 param2: Int, param3: Int) {
print(param1, param2, param3)
}
// 函数参数使用外部名称
outerNameFunc(name1: 1, name2: 2, param3: 3)
func normalFunc(param1: Int, param2: Int, param3: Int) {
print(param1, param2, param3)
}
// 默认函数参数的内部名称和外部名称一致,调用函数时需要指定参数名称
normalFunc(param1: 1, param2: 2, param3: 3)
// 调用函数时省略参数名称
func annoFunc(_ param1: Int, _ param2: Int, _ param3: Int) {
print(param1, param2, param3)
}
annoFunc(1, 2, 3)
- 函数参数指定默认值
func func5(param1: Int, param2: Int = 2, param3: Int = 3) {
print(param1, param2, param3)
}
// 调用时,可以只传入没有默认值的参数
func5(param1: 1)
// 调用时,参数位置要严格对应
func5(param1: 1, param2: 22)
// 函数参数指定默认值
func func6(param1: Int, param2: Int = 2, param3: Int) {
print(param1, param2, param3)
}
// 调用时,参数位置要严格对应
func6(param1: 1, param3: 33)
- 可变参数
// 函数传入多个可变数量的参数,类似于 Kotlin 的 vararg
func mutableParamFunc(param: Int...) {
var sum = 0
for ele in param {
sum += ele
}
print(sum)
}
mutableParamFunc(param: 1, 2)
mutableParamFunc(param: 1, 2, 3, 4)
// swift 的函数参数值(除引用类型外)默认是不可修改的
func immutableParam(param: Int) {
// param += 1 // 编译失败 error: left side of mutating operator isn't mutable: 'param' is a 'let' constant
}
// 为了可以在函数参数内部修改参数值,可以使用 inout 修饰参数
func immutableParam(param:inout Int) {
param += 1 // 编译通过
print(param) // 2
}
// 调用时需要使用 & 符号
var number = 1
immutableParam(param: &number)
print(number) // 2, number的值也被修改了
- 函数类型引用,函数嵌套
// 函数可以作为类型进行声明,就像使用其他类型一样
let func7Name: (Int, Int) -> Bool
// 将闭包赋值给函数变量
func7Name = {(param1: Int, param2: Int) in
return param1 > param2
}
// 调用函数变量
func7Name(1, 2) // false
// 函数作为参数传入
func func8(funParam: (Int, Int) -> Bool) {
print(funParam(2, 1)) // true
}
// 将 func7 传入 func8
func8(funParam: func7Name)
// 函数作为返回值类型
func func9() -> (Int, Int) -> Bool {
return func7Name // 将 func7Name 返回
}
// 函数嵌套
func outerFunc() {
let outerScope = "outer scope"
func innerFunc() {
print(outerScope, "in inner func")
}
// 在外部函数内调用内部嵌套函数,在外部函数以外无法调用它
innerFunc()
}
// 调用外部函数
outerFunc()
- 闭包:后置闭包、逃逸闭包与自动闭包
// 定义闭包,类似于 Kotlin 的 lambda 表达式。
// 闭包一般是为了处理回调,传递功能代码块
// 闭包标准语法结构:{(param list) -> valueType in block}
let closureFunc1 = {(param1: Int, param2: Int) -> Int in
return param1 + param2
}
// 调用闭包
closureFunc1(1, 2) // 3
// 闭包可省略返回值
let closureFunc2 = {(param1: Int, param2: Int) in
return param1 + param2
}
closureFunc2(1, 3) // 4
// 如果闭包只有一行代码,可以省略 return
let closureFunc3 = {(param1: Int, param2: Int) in
return param1 < param2
}
closureFunc3(1, 2) // true
// 入参为闭包
func func10(closureParam: (Int, Int) -> Bool) {
closureParam(2, 1)
}
// 使用默认参数名
func10(closureParam: { $0 > $1 }) // true
// 后置闭包,当最后一个参数为闭包时,简化写法:
func10() {
$0 > $1
}
// 非逃逸闭包:函数的生命周期结束后,闭包也将被销毁
// 定义的闭包默认都是非逃逸的
// 逃逸闭包:函数的执行结束后,闭包在函数外仍可使用
// 定义逃逸闭包使用 @escaping ,一般用于异步回调
func func11(closureParam: @escaping (Int, Int) -> Bool) {
}
// 定义自动闭包使用 @autoclosure,对简单闭包的自动生成。
// 自动闭包默认非逃逸。自动闭包不能够有参数,单表达式
func autoCloseFunc(closureParam: @autoclosure () -> Int) {
print(closureParam()) // 6
}
autoCloseFunc(closureParam: 1 + 2 + 3)
八) Swift5 高级[运算符]与枚举
- 位运算
// Swift 位运算
var sixteen: UInt8 = 0b00010000 // 二进制
print(sixteen) // 8
// Swift 按位与 & : 操作数相同的位进行逻辑与运算
// 即两个对应位的值都为1,结果为1,否则为0。示例:
var result1 = sixteen & 0b00001111 // 0
var result2 = 0b00000111 & 0b00000001 // 1
// Swift 按位或 | :操作数相同的位进行逻辑或运算
// 即两个对应位的值有一个为1,结果为1,否则为0。示例:
var result3 = 0b00000111 | 0b00000000 // 0b00000111 7
var result4 = 0b00000001 | 0b00000010 // 0
// Swift 按位取反 ~ :将操作数的每一位都取反,如果当前位是1,则取反为0
var result5 = ~sixteen // 0b11101111 255 - 16 = 239
// Swift 按位异或 ^
// 即两个对应位的值相同,结果为0,否则为1。示例:
var result6 = 0b00000111 ^ 0b00000000 // 0b00000111 7
var result7 = 0b00000111 ^ 0b00001111 // 0b00001000 8
// Swift 按位左移 << ,按位右移 >>
var result8 = 0b00000111 << 1 // 0b00001110 7 << 1 = 7 * 2 = 14
var result9 = 0b00000111 >> 1 // 0b00000011 7 >> 1 = 7 / 2 = 3
// Swift 按位左移 << ,按位右移 >> 对于位数较低类型,会出现数据丢失的情况
var result10: UInt8 = 0b00001000 << 5 // 0
var result11: UInt8 = 0b00010000 >> 5 // 0
- 溢出运算符
// 溢出运算符
var num: UInt8 = 255
var result12 = num &+ 1 // 溢出后变为0
result12 = result12 &- 1 // 溢出后再减1,255
result12 = result12 &* 2 // 即 0b11111111 << 1 = 0b11111110 = 254
- 重载运算符
// 重载运算符 + , 元组相加,扩展加号的新功能
func +(param1: (Int, Int), param2: (Int, Int)) -> (Int, Int) {
return (param1.0 + param2.0, param1.1 + param2.1)
}
var tuple1: (Int, Int) = (1, 2)
var tuple2: (Int, Int) = (1, 2)
let tuple = tuple1 + tuple2 // (2, 4)
- 自定义运算符
// 自定义运算符
// 自定义前缀运算符,即只需要一个操作数,运算符在操作数前面
prefix operator ++
prefix func ++(param: Int) -> Int {
return param + 1
}
++1 // 2
// 自定义中缀运算符,即需要两个操作数,运算符在两个操作数中间
infix operator **
func **(param1: Int, param2: Int) -> Int {
return param1 * param1 + param2 * param2
}
1 ** 2 // 5
// 自定义后缀运算符,即只需要一个操作数,运算符在操作数后面
postfix operator --
postfix func --(param: Int) -> Int {
return param - 1
}
1-- // 0
- 枚举
// 定义字符串枚举,原始值类型为 String
enum Week: String {
// 在一行中直接定义,也可以分别使用 case 定义
case MON = "星期一", TUE = "星期二", WED = "星期三", THUR = "星期四", FRI = "星期五", SAT = "星期六", SUN = "星期日"
}
// 定义整型枚举,原始值类型为 UInt8
enum Number: UInt8 {
// 如果原始值是整型,后续的 case 值会依次递增
case 壹 = 1, 贰, 叁, 肆, 伍, 陆
}
print(Number.肆.rawValue) // 4
var day = Week.MON
// 构造枚举
var numTwo = Number.init(rawValue: 2)
// case 需要详尽列出
switch day {
case .MON:
print("monday", day.rawValue) // monday 星期一
case .TUE:
print("tuesday")
case .WED:
print("wednesday")
case .THUR:
print("thursday")
case .FRI:
print("friday")
case .SAT:
print("saturday")
case .SUN:
print("sunday")
}
// 定义枚举,设置相关值
enum Direction {
case left(type: Int, text: String)
case right(type: Int, text: String)
}
var direction = Direction.left(type: 1, text: "左")
switch direction {
case let .left(type, text):
print("type: \(type),向\(text)") // "type: 1,向左"
case let .right(type, text):
print("type: \(type),向\(text)")
}
九) Swift 结构体与类
- 结构体
// 定义结构体
struct Phone {
// 定义价格属性
var price: Int
// 定义品牌属性
var brand: String
// 定义型号属性
var model: String
// 定义降价促销方法
mutating func discount() {
price -= 800
}
}
// 调用默认的构造方法,创建结构体实例
let iPhone = Phone(price: 6999, brand: "iPhone", model: "iPhone 13")
print("手机品牌:\(iPhone.brand), 型号:\(iPhone.model),价格:\(iPhone.price)" )
// 结构体属于值类型,用 let 修饰后无法修改 phone 的属性值
var phone = iPhone
phone.price -= 1000
// 值修改后不会影响原结构体的值,iPhone.price: 6999, phone.price: 5999
print("iPhone.price: \(iPhone.price), phone.price: \(phone.price)")
- 类
// 定义一个类
class PhoneClass {
// 定义价格属性
var price: Int = 0
// 定义品牌属性
var brand: String = ""
// 定义型号属性
var model: String = ""
// 定义降价促销方法
func discount() {
price -= 800
}
// 当三个属性都有默认值的时候,可以不写 init
init(price: Int, brand: String, model: String) {
self.price = price
self.brand = brand
self.model = model
}
}
// 创建 class 实例
var huaweiPhone = PhoneClass(price: 5999, brand: "huawei", model: "p40 pro")
// 类属于引用类型,变量传递后,修改值会影响引用的变量
let huaweiNewPhone = huaweiPhone
huaweiPhone.price += 1000
// 值修改后会影响原变量的值,huaweiPhone.price: 6999, huaweiNewPhone.price: 6999
print("huaweiPhone.price: \(huaweiPhone.price), huaweiNewPhone.price: \(huaweiNewPhone.price)")
十) Swift5 属性与方法
- Swift 存储属性
// Swift5 存储属性
class Phone {
var system = "iOS"
// 常量存储属性,一旦实例化,不能修改
let brand: String
// 存储属性,可以修改
var price: Int
// 当类被实例化时,要保证所有的属性都初始化完成,除非属性有默认值
init(brand: String, price: Int) {
self.brand = brand
self.price = price
print("brand: \(brand), price: \(price)")
}
}
// 修改类的属性值
let iPhone = Phone(brand: "iPhone", price: 5999)
iPhone.price -= 600
// 延时存储属性:当类初始化时,延时存储属性不被初始化,当被调用时才初始化
class Consumer {
var money: Int
lazy var phone: Phone = Phone(brand: "iPhone", price: 6999)
init(money: Int) {
self.money = money
}
}
// 只初始化了money
var richMan = Consumer(money: 100_000)
// 延时属性 phone 被初始化
print(richMan.phone) // brand: iPhone, price: 6999
- Swift 计算属性
// Swift5 计算属性
class Android {
// 常量存储属性,一旦实例化,不能修改
let system: String = "android"
// 存储属性
var version = "12"
// api 级别
var apiLevel: String = "31"
// 计算属性,向外提供接口访问类实例的某种状态,这种状态和类实例的属性值相关联
var info: String {
get {
return "system: \(system), version: \(version), level: \(apiLevel)"
}
set {
// 默认使用 newValue 指代新值
version = newValue.split(separator: "-").first?.description ?? ""
apiLevel = newValue.split(separator: "-").last?.description ?? ""
}
}
// 计算属性 价格,简单模拟
var price: ClosedRange<Int> {
get {
// 当版本高于30时,价格在[4000,6999]之间
if (apiLevel > "30") {
return 4000...6999
} else {
return 1000...3999
}
}
// 自定义传值名称 newPrice
set(newPrice) {
// 当价格高于3999时,版本为31
if (newPrice.lowerBound > 3999) {
apiLevel = "31"
version = "12"
} else {
apiLevel = "30"
version = "11"
}
}
}
}
var newPhone = Android()
print(newPhone.info) // system: android, version: 12, level: 31
newPhone.info = "11-30"
print(newPhone.info) // system: android, version: 11, level: 30
newPhone.price = 4000...4999
print(newPhone.info) // system: android, version: 12, level: 31
- Swift 属性监听器
// Swift5 属性监听器
class iOS {
var brand: String {
// 此属性将要被赋值时会调用,默认带一个 newValue 字段。
// 注意:初始化时不会被调用,从第二次赋值时才开始被调用
willSet {
print("new value : \(newValue)")
}
// 此属性已经被赋值后会调用,默认带一个 oldValue 字段
didSet {
print("old value : \(oldValue)")
}
}
var price: Int {
// 自定义传值名称
willSet(newPrice) {
print("new price : \(newPrice)")
}
// 自定义传值名称
didSet(oldPrice) {
print("old price : \(oldPrice)")
}
}
init(brand: String, price: Int) {
self.brand = brand
self.price = price
print("brand: \(brand), price: \(price)")
}
}
let newIPhone = iOS(brand: "iphone 12", price: 5999)
newIPhone.brand = "iphone 13"
newIPhone.price = 6999
- Swift 属性包装器
// Swift5 属性包装器
@propertyWrapper
struct StringNotEmpty {
var value: String
init() {
self.value = "default string"
}
var wrappedValue: String {
get { return value }
set {
if (newValue.count > 0) {
self.value = newValue
} else {
self.value = "default string"
}
}
}
}
class Student: CustomStringConvertible {
@StringNotEmpty
var name: String
var description: String {
return "student's name is \(name)"
}
}
let student = Student()
student.name = ""
print(student) // student's name is default string
- Swift 静态属性与静态方法
// Swift5 静态属性与静态方法
class BaseClass {
// 静态存储属性
static var param = "param"
// 静态计算属性
static var computeParam: String {
return "computeParam"
}
// 可被继承的静态计算属性
class var openParam: String {
return "openParam"
}
// 声明静态方法,即类方法
static func method() {
print("static method")
}
// 声明可被继承的静态方法
class func openMethod() {
print("static openMethod")
}
}
class SubClass : BaseClass {
// 重写父类的 openParam 属性,类似于 Kotlin 的 open 修饰
override class var openParam: String {
return "SubClass openParam"
}
override class func openMethod() {
print("SubClass openMethod")
}
}
// 调用静态属性
BaseClass.param
BaseClass.computeParam
BaseClass.openParam
SubClass.openParam
// 调用静态方法
BaseClass.method()
BaseClass.openMethod()
SubClass.openMethod()
- Swift 下标方法
// Swift5 下标方法
// 为自定义的数据类型使用 subscript 定义下标访问元素的方法
class CustomList {
var list: Array<String>
init(list: String...) {
self.list = list
}
// 定义下标方法
subscript(index: Int) -> String {
set {
list[index] = newValue
}
// 可以只定义get
get {
return list[index]
}
}
}
let list = CustomList(list: "1", "2", "3")
list[0] = "item 1"
print(list[1])
十一) Swift5 [构造方法]
- Swift 类的构造方法
// Swift5 类的构造方法
// 1. 在构造方法中需要给没有默认值的属性初始化值
class Demo1 {
// 含有默认值
var param1: String = "default"
// 未指定默认值,需要在 init() 中初始化
var param2: String
// 未指定默认值,类型为 Optional,可空,
// 默认值为 nil, 不需要在 init() 中初始化
var param3: String?
init(param: String) {
self.param2 = param
}
}
// 2. 如果属性有默认值,则自动生成一个无参构造方法 init(),即初始化后的实例的属性都有默认值
class Demo2 {
var param1 = "param1 String"
var param2 = "param2 String"
}
var demo2 = Demo2()
print("param1: \(demo2.param1), param2: \(demo2.param2)")
- Swift 结构体的构造方法
// Swift5 结构体的构造方法
struct StructDemo {
var param1: String
var param2: String
// 结构体的构造方法会默认生成,将所有属性作为参数
init(param1: String, param2: String) {
self.param1 = param1
self.param2 = param2
}
init() {
// 在自定义的构造方法中调用默认的构造方法
self.init(param1: "init value1", param2: "init value2")
}
}
// 调用结构体默认的构造方法
var structIns1 = StructDemo(param1: "value1", param2: "value2")
// 调用结构体自定义的构造方法
var structIns2 = StructDemo()
- Swift 指定构造 方法 和 便利构造 方法 指定构造方法 designated 与 便利构造方法 convenience 。使用原则:
- 子类的指定构造方法中必须调用父类的指定构造方法
- 便利构造方法中必须调用当前类的其他构造方法
- 便利构造方法最终是要调用指定某个构造方法
// Swift5 指定构造方法和便利构造方法
// 定义一个含有指定构造和便利构造的父类
class Base {
// 默认的指定构造方法
init() {
print("base class designated constructor method")
}
// 声明一个便利构造方法
convenience init(param: Int) {
print("base class convenience constructor method")
// 最终调用指定构造方法
self.init()
}
}
var baseIns = Base(param: 0)
// 继承父类
class Sub : Base {
override init() {
// 如果重写父类的指定构造方法,必须调用 super
super.init()
}
convenience init(param: Int) {
// 在便利构造方法中调用指定的构造方法
print(param)
self.init()
}
convenience init(param1: Int, param2: Int) {
// 在便利构造方法中调用另一个便利构造方法
print(param1, param2)
self.init(param: param1)
}
}
var subIns = Sub(param1: 0, param2: 1)
- Swift 构造方法的安全性检查
- 必须在调研父类的指定构造方法前完成自身属性的赋值
- 必须在调用父类指定的构造方法之后,在子类中才能修改父类的属性值
- 在调用父类的构造方法之后,才能使用 self 关键字
- 在便利构造方法中要修改属性值必须在调用指定构造方法之后
// Swift5 构造方法的安全性检查
class BaseCheck {
var field: String
init(field: String) {
self.field = field
}
}
class SubCheck: BaseCheck {
var subField: String
init() {
// 1. 必须在调研父类的指定构造方法前完成自身属性的赋值
subField = "sub field value"
super.init(field: "base field value")
// 2. 必须在调用父类指定的构造方法之后,在子类中才能修改父类的属性值
field = "base field set in sub"
// 3. 在调用父类的构造方法之后,才能使用 self 关键字
self.subField = "sub field value set again"
print(subField, field)
}
convenience init(param: Int) {
// 4. 在便利构造方法中要修改属性值必须在调用指定构造方法之后
self.init()
subField = "subField set in convenience \(param)"
field = "field set in conveniencem \(param)"
print(subField, field)
}
}
var checkIns = SubCheck(param: 1)
- Swift 定义可失败的构造方法
// Swift5 定义可失败的构造方法
class CanBeNil {
var field: Int
// 构造可能会失败返回 nil
init?(param: Int) {
guard param > 0 else {
return nil
}
field = param
}
}
let ins = CanBeNil(param: 0) // nil
- Swift 必要构造方法 与 析构方法
// Swift5 必要构造方法与析构方法
class DemoClass {
var field: Int
// 声明必要构造方法,子类必须继承或重写
required init(param: Int) {
field = param
}
// 析构方法,类实例被销毁
deinit {
// 实例被释放
print("demo instance destroy")
}
}
// 定义可选类型
var demoIns: DemoClass? = DemoClass(param: 1)
demoIns = nil // 被赋值 nil 时,deinit会调用
十二) Swift 内存管理与异常处理
Swift5 内存引用与异常处理
- Swift 内存销毁时机
// Swift5 内存销毁时机
// 引用类型的内存销毁时机
class ClassDemo {
var a = "value a"
deinit {
// 实例被释放
print("deinit class a")
}
}
// 可空类型
var ins1: ClassDemo? = ClassDemo()
var ins2 = ins1
var ins3 = ins2
ins1 = nil // 取消 ins1 引用
ins2 = nil // 取消 ins2 引用
print(String(describing: ins3?.a)) // 此处 ins3 引用的实例依然在,Optional("value a")
// 对实例引用被全部取消,ClassA 实例此处才销毁
ins3 = nil // deinit class a
- Swift 单向引用
// Swift5 单向引用
class ClassA {
deinit {
print("deinit ClassA")
}
func foo() {
print("func foo in ClassA")
}
}
class ClassB {
// 此处引用 ClassA 的实例
var ins: ClassA?
init(ins: ClassA?) {
self.ins = ins
}
deinit {
print("deinit ClassB")
}
}
var clzA: ClassA? = ClassA()
var clzB: ClassB? = ClassB(ins: clzA)
// 此处 clzA 所引用的内存并未释放
clzA = nil
// 依然可以调用 clzB 中的 clzA 实例的 foo 方法
clzB?.ins?.foo() // func foo in ClassA
// 此时 ClassB 实例被释放,不再有引用指向 ClassA 随即所占内存也被释放
clzB = nil // deinit ClassB \n deinit ClassA
- Swift 循环引用
// Swift5 循环引用
class ClassC {
var insD: ClassD?
deinit {
print("deinit ClassC")
}
func foo() {
print("func foo in ClassC")
}
}
class ClassD {
// 此处引用 ClassC 的实例
var insC: ClassC?
init(ins: ClassC?) {
self.insC = ins
}
deinit {
print("deinit ClassD")
}
}
var clzC: ClassC? = ClassC()
var clzD: ClassD? = ClassD(ins: clzC)
clzC?.insD = clzD
// 此处 clzC 所引用的内存并未释放,对应实例被 clzD 的 insC 引用
clzC = nil
// 依然可以调用 clzD 中的 insC 实例的 foo 方法
clzD?.insC?.foo() // func foo in ClassC
// 此时 clzD 的实例依然被 clzC 的 insD 引用,clzC 和 clzD 实例都未被释放
clzD = nil
- Swift 弱引用 解决 循环引用 问题
// Swift5 使用 弱引用 解决 循环引用
class ClassE {
// 弱引用 weak
weak var insF: ClassF?
deinit {
print("deinit ClassE")
}
func foo() {
print("func foo in ClassE")
}
}
class ClassF {
// 此处引用 ClassE 的实例
var insE: ClassE?
init(ins: ClassE?) {
self.insE = ins
}
deinit {
print("deinit ClassF")
}
}
var clzE: ClassE? = ClassE()
var clzF: ClassF? = ClassF(ins: clzE)
clzE?.insF = clzF
// 此处 clzE 所引用的内存并未释放,对应实例被 clzF 的 insE 引用
clzE = nil
// 依然可以调用 clzF 中的 insE 实例的 foo 方法
clzF?.insE?.foo() // func foo in ClassE
// 此时 clzF 的实例被 clzE 的 insF 弱引用,会被销毁,clzE 和 clzF 实例都能被释放
clzF = nil // deinit ClassF \n deinit ClassE
- Swift 无主引用,针对类型为非 Optional
// Swift5 无主引用,针对类型为非 Optional
class ClassG {
// 无主引用 unowned 假定属性不为 nil
unowned var insH: ClassH
init(ins: ClassH) {
self.insH = ins
}
func foo() {
print("func foo in ClassG")
}
deinit {
print("deinit ClassG")
}
}
class ClassH {
// 此处引用 ClassE 的实例
var insG: ClassG?
deinit {
print("deinit ClassH")
}
}
var clzH: ClassH? = ClassH()
var clzG: ClassG? = ClassG(ins: clzH!)
clzH?.insG = clzG
// 此处 clzG 所引用的内存并未释放,对应实例被 clzH 的 insG 引用
clzG = nil
// 依然可以调用 clzH 中的 insG 实例的 foo 方法
clzH?.insG?.foo() // func foo in ClassG
// 此时 clzH 的实例被 clzG 的 insH 无主引用,会被销毁,clzG 和 clzH 实例都能被释放
clzH = nil // deinit ClassH \n deinit ClassG
- Swift 闭包产生的循环引用
// Swift5 闭包产生的循环引用
class ClassJ {
var field = "field j"
lazy var closure: () -> Void = {
print(self.field)
}
deinit {
print("deinit ClassJ")
}
}
var objJ: ClassJ? = ClassJ()
objJ?.closure()
// 因为闭包引用了类的成员属性,导致实例无法释放,进而导致闭包无法释放,产生循环引用
objJ = nil // 此处并没有打印 deinit 中信息
- Swift 解决闭包产生的循环引用
// Swift5 解决闭包产生的循环引用
class ClassK {
var field = "field k"
lazy var closure: () -> Void = {
// 使用捕获列表对 self 进行无主引用的转换
[unowned self] () -> Void in
print(self.field)
}
deinit {
print("deinit ClassK")
}
}
var objK: ClassK? = ClassK()
objK?.closure()
objK = nil // deinit ClassK
- Swift 自定义异常类型
// Swift5 自定义异常类型
enum CustomError: Error {
case ErrorOne
case ErrorTwo
case ErrorThree
}
print("error")
//throw CustomError.ErrorOne // 抛出的异常未捕获会终止,不会打印 complete
print("complete")
- Swift do-catch 捕获异常,try 执行会抛异常的函数
// Swift5 使用 do-catch 捕获异常,try 执行会抛异常的函数
// 通过函数抛出异常
func funcError() throws -> String {
throw CustomError.ErrorTwo
}
// 使用 do-catch 捕获异常
do {
// 使用 try 执行可能会抛出异常的函数
try funcError()
} catch CustomError.ErrorOne {
print("ErrorOne")
} catch CustomError.ErrorTwo {
print("ErrorTwo")
} catch CustomError.ErrorThree {
print("ErrorThree")
}
// 使用 try? 将函数执行的结果映射为 Optional 类型
let result = try? funcError()
if (result == nil) {
print("exec failed")
}
// try! 强行终止异常的传递,如果发生异常,则程序中断
// try! funcError()
- Swift 函数延时执行结构
// Swift5 函数延时执行结构:避免在抛异常的时候,保证某些必须的代码块要执行,如释放资源
func lazyFunc() throws -> Void {
defer {
// 函数结束时会得到执行
print("lazy part of func")
}
print("exec lazyFunc")
throw CustomError.ErrorThree
}
// exec lazyFunc
// lazy part of func
try? lazyFunc()
十三 ) Swift5 类型转换泛型、扩展与协议
1. Swift 判断值类型
// Swift5 判断值类型
var anyObj: Any = 1
if anyObj is Int {
print("anyObj's type is Int")
} else if anyObj is String {
print("anyObj's type is String")
}
2. Swift 判断引用类型
// Swift5 判断引用类型
class Base {
var text = "base text"
}
class Sub1: Base {
var subText1 = "sub1 text"
}
class Sub2: Base {
var subText2 = "sub2 text"
func subFunc() {
print("sub func invoke")
}
}
3. Swift 类型转换
// Swift5 类型转换 as , as! , as?
var obj = Base()
var subObj1 = Sub1()
var subObj2 = Sub2()
// Swift 数组中类型为 Base 的都可以存入
var arrayObj: [Base] = [obj, subObj1, subObj2]
for index in 0..<arrayObj.count {
let obj = arrayObj[index]
if obj is Sub1 {
// 如果是 Sub1 就转换为 Sub1 类型,向下转型
let subObj = obj as! Sub1
print(subObj.subText1)
} else if obj is Sub2 {
let subObj = obj as! Sub2
print(subObj.subText2)
} else {
print(obj.text)
}
}
4. Swift AnyObject 与 Any
// Swift 使用 AnyObject 类型声明数组,其中可以存放任何引用类型,不可以存放值类型
var arrayAnyObj: [AnyObject] = [obj, subObj1, subObj2]
// Swift 使用 Any 类型声明数组,其中可以存放任何类型,包含 值类型 和 引用类型
var arrayAny: [Any] = [1, "2", true, obj, (0, 0), {(param: Int) -> Int in return param}]
5. Swift 泛型与扩展
// Swift 使用泛型定义方法,打印自身
func printSelf<T>(_ param: T) {
print(param)
}
printSelf("text")
printSelf(1000)
// Swift 使用泛型定义结构体,实现简单集合
struct List<T> {
private var datas: [T] = []
mutating func add(_ newEle: T) {
datas.append(newEle)
}
mutating func get(_ index: Int) -> T {
return datas[index]
}
}
// Swift 使用扩展,给结构体添加一个扩展方法
extension List {
func getDatas() -> [T] {
return datas
}
}
// 定义整型的集合
var list = List<Int>()
// 添加元素
list.add(1)
list.add(2)
list.add(3)
// 读取元素
var ele = list.get(1)
print(ele) // 2
// 调用扩展方法
var datas = list.getDatas()
print(datas) // [1, 2, 3]
6. Swift 泛型约束
// Swift5 添加泛型约束
// 定义一个存放 Base 子类的结构体
struct ObjList<T: Base> {
private var datas: [T] = []
mutating func add(_ newEle: T) {
datas.append(newEle)
}
mutating func get(_ index: Int) -> T {
return datas[index]
}
}
var objList = ObjList<Sub1>()
objList.add(subObj1)
// 定义多个泛型约束
class MultipleType<T, R> where T: BaseProtocol, R: SubProtocol {
}
7. Swift 协议 protocol
// Swift5 定义协议 protocol,类似于 java, kotlin 中定义接口
protocol BaseProtocol {
// 实现协议时才指定类型
associatedtype T
// 定义普通方法
func printType(input: T) -> Void
// 定义计算属性
var field1: T {get}
var field2: String {get set}
// 定义静态方法
static func method()
}
// 协议继承,自动继承 BaseProtocol 中的属性和方法
protocol SubProtocol: BaseProtocol {
}
// ClaProtocol 协议只能被类遵守
protocol ClaProtocol: AnyObject {
}
8. Swift 遵守实现协议
// Swift5 遵守协议并实现
class ClassImpl: BaseProtocol {
func printType(input: String) {
print(input)
}
// 实现计算属性
var field1: String {
get {return "field1"}
set {}
}
var field2: String {
get {return "field2"}
set {}
}
// 实现静态方法
static func method() {}
}
// 为类扩展属性和方法
extension ClassImpl {
var extField: Int {
get {
return 100
}
}
func extFunc() {
print("ext func")
}
}
var implCla = ClassImpl()
implCla.printType(input: "input text")
print(implCla.extField)
implCla.extFunc()
9. Swift 定义协议可选实现
// 使用 @objc 定义可选实现
@objc protocol OptionalProtocol: AnyObject {
@objc optional func method();
}
extension OptionalProtocol {
// 利用扩展,提供默认实现
func method() {
print("default method extension")
}
}
class ClassOptPro: OptionalProtocol {
}
// 调用默认实现
var claOptIns = ClassOptPro()
claOptIns.method()
十四 ) Swift 高级特性
一、Swift 独占访问
Swift 内存安全检查:当两个变量访问同一块内存时,会产生独占内存访问限制。
发生读写权限冲突的情况: inout 参数读写冲突 结构体中函数修改成员属性读写冲突 值类型属性读写冲突
1. inout 参数读写冲突
// 1. Swift inout 参数读写冲突
var inputStr = "input"
func plusSlef1(_ param: inout String) {
// 在 >= Swift4 版本会抛异常:同时访问0x103ed30a0,但是修改需要独占访问。
param += inputStr
}
// 调用下面的代码会崩溃
// plusSlef1(&inputStr)
// 同时访问同一个内存地址,造成读写冲突
func plusSlef2(_ param1: inout String, _ param2: inout String) {
// 在 >= Swift4 版本会抛异常:重叠访问'inputStr',但修改需要独占访问;考虑复制到一个局部变量
let result = param1 + param2
print(result)
}
// 调用下面的代码会崩溃
// plusSlef2(&inputStr, &inputStr)
2. 结构体中函数修改成员属性读写冲突
// Swift 结构体中函数修改成员属性读写冲突
struct StructA {
var field: Int
// mutating 修饰可修改成员属性,inout 开放写访问,会产生读写冲突
mutating func edit(_ param: inout StructA) {
field = param.field
}
}
var structA = StructA(field: 100)
// 调用下面的代码会产生编译错误:
// 1. Inout参数不允许彼此别名
// 2. 重叠访问'structA',但修改需要独占访问;考虑复制到一个局部变量
// structA.edit(&structA)
3. 值类型属性读写冲突
// Swift 值类型属性读写冲突
class ClassA {
// 定义元组,属于值类型
var tuple = (key1: 1, key2 : 2)
func test1(_ param1: inout Int, _ param2: inout Int) {
print(param1, param2)
}
func test2() {
// 如果被调用会崩溃,同时访问0x600000667cd0,但是修改需要独占访问。
test1(&tuple.key1, &tuple.key2)
}
func test3() {
// 访问 局部 值变量 可以正常使用
var localTuple = (key1: 3, key2 : 4)
test1(&localTuple.key1, &localTuple.key2)
}
}
let cla = ClassA()
// 调用下面的代码会崩溃
// cla.test2()
cla.test3() // 正常调用,打印 3 4
二、Swift 增强字符串
// 多行字符串 界定符 转义符
// Swift 多行字符串,同 kotlin 的原始字符串,不需要手动添加换行符。可用于排版
var text1 = """
start
\(1)
2
end
"""
print(text1)
// 转义符
var text2 = "对单引号进行转义\'"
print(text2) // 对单引号进行转义'
// 使用界定符代替转义符
var text3 = #"对单引号进行转义'"#
print(text3) // 对单引号进行转义'
// 使用界定符时,转义符失去作用
var text4 = #"换行符1 \n 换行符2"#
print(text4) // 换行符1 \n 换行符2
// 使用界定符时,使用 \# 保留转义符的作用
var text5 = #"换行符1 \#n 换行符2"#
print(text5) // 会换行打印: 换行符1 换行符2
三、Swift 动态成员查找
@dynamicMemberLookup // Swift使用 @dynamicMemberLookup 为类增加动态查找成员的能力
@dynamicCallable // Swift使用 @dynamicCallable 为类增加动态方法调用的能力
class Data {
var field1: Int = 0
var field2: String = ""
subscript(dynamicMember member: Int) -> String {
return "class don't have the field: \(member), type int"
}
subscript(dynamicMember member: String) -> String {
return "class don't have the field: \(member), type String"
}
// 传入一组参数
func dynamicallyCall(withArguments argArray: [Int]) {
print("invoke unknown func with args: \(argArray)")
}
// 传入键值对参数
func dynamicallyCall(withKeywordArguments pairs: KeyValuePairs<String, Int>) {
let argPairs = pairs.map{ key, value in
return "\(key): \(value)"
}
print(argPairs)
}
}
let data = Data()
// 当访问不存在的属性时,就会调用对应的 subscript 方法返回对应类型的值
// class don't have the field: someInt, type String. class don't have the field: someString, type String
print(data.someInt, data.someString)
// 调用不存在的方法,把实例当做方法调用
// 传入一组参数
data(1, 2, 3) // invoke unknown func with args: [1, 2, 3]
// 传入键值对参数
data(key1: 1, key2: 2) // ["key1: 1", "key2: 2"]
四、Swift 增强协议
// Swift 使用多个协议界定参数
protocol ProtocolA {
var field: String {get set}
}
protocol ProtocolB {
func method()
}
// 实现多个协议
class ClassImpl : ProtocolA, ProtocolB {
var field: String = "impl field"
func method() {
print("impl method")
}
}
// 使用 & 界定多个协议
func testImpl(impl: ProtocolA & ProtocolB) {
print(impl.field)
impl.method()
}
testImpl(impl: ClassImpl())
四、Swift 增强协议
// Swift 使用多个协议界定参数 protocol ProtocolA { var field: String {get set} } protocol ProtocolB { func method() } // 实现多个协议 class ClassImpl : ProtocolA, ProtocolB { var field: String = "impl field"
func method() {
print("impl method")
}
} // 使用 & 界定多个协议 func testImpl(impl: ProtocolA & ProtocolB) { print(impl.field) impl.method() }
testImpl(impl: ClassImpl())