运算符、条件判断及类型
运算符
代码注释
//
、/* */
常量:let 变量:var
数学运算符:
+ - * / % += -= *= /=
逻辑运算符:
Bool && || !
比较运算符:
>= > <= < ==
条件判断
- 条件运算符:
if else、 else if 、 ?: 、 switch 、default
if else:
if condition {
} else if condition1 {
} else {
}
区间: 1…7
2..<9
switch:
switch{
case 1:
}
类型 Types
- 常见类型:
Int 、Double、Bool、String
- 类型转换:
String(50)
- 字符串插值:
"\(day)"
用函数将代码归类为功能
- 第一版写法:增加参数
func driveTowards(direction: Srting, meters: Int){}
driveTowards(directions: "前", meters: 100)
- 第二版写法: 增加参数标签
若希望省略参数标签,可使用 swift 语言的省略符号 _
。
func driveTowards(_ direction: String, for meters: Int){}
driveTowards("前", for: 100)
- 第三版写法:增加默认值
func driveTowards(_ direction: String = "前", for meters: Int){}
driveTowaords(for: 100)
- 返回值:
func rollDice() -> Int {
Int.random(in: 1...6)
}
用集合与循环处理数据
集合类型数组 Array
var weightRecordsA = [70.4, 70.3, 70.1]
var weightRecordsB: [Double] = []
常见方法
- 添加:
append
,insert(_:, at:)
- 删除:
remove
,removeAll
,removeSubrange
- 使用:
randomElement
,firstIndex(of: )
- 修改:
sort
,shuffle
,map
,filter
- 判断:
count
,min
,isEmpty
,contains
var arr = [70.4, 70.3, 70.1]
// 添加
arr.append(80.2)
arr += [89.1, 33.3]
arr.insert(70.2, at: 3)
// 删除
arr.remove(at: 2)
arr.removeSubrange(3...7)
arr.removeAll()
// 使用
arr[1]
arr.randomElement()
arr.firstIndex(of: 70.2)
// 原位修改
arr[0] = 89.2
arr.sort()
arr.shuffle()
// 新数组修改
newArr = arr.map { ($0 - targetWeight) }
newArr = arr.filter { $0 - 79.2 }
// 判断数组当前状态
arr.count
arr.isEmpty
arr.min()
arr.contains(77.2)
集合类型字典 Dictionary
let PhoneBookA: [String: Int] = [:]
let PhoneBookB= ["老王":12345]
- 增:
phoneBookB["new"] = 2134213
- 删:
phoneBookB[:"new"] = nil
- 查:
phoneBookB["老王"]
- 改:
phoneBookB["老王"] = 544332
- 状态:
.count
.isEmpty
.contains(where: { $0.key == "老王" })
循环
for in
,while condition {}
,repeat {} while condition
编程范型,闭包及可选类型
闭包
- 闭包与函数的区别:省略函数名、增加了
in
语法、前移花括号
// 函数
func isTheFirstSmallerThanSecond(first: Int, second: Int) -> Bool {
return first < second
}
// 闭包
let closure = { (first: Int, second: Int) -> Bool in
return first < second
}
// by: 使用
numberArr.sort(by: closure)
- 用法 1 不构建常量:适用于单次使用函数
numberArr.sort(by: { (first: Int, second: Int) -> Bool in
return first < second
})
- 用法 2 尾部闭包:对有闭包作为参数的函数,若其最后一个参数 Argument 为闭包,则可省略参数标签及括号。
numberArr.sort { (first: Int, second: Int) -> Bool in
return fisrt < second
}
- 用法 3 省略类型:定义时已明确的闭包的类型,可省略
numbersArr.sort { (first, second) in
return first < second
进一步省略参数位置的括号、函数功能代码仅存在一行返回值时,关键词 return 可省略
numbers.sort { first, second in first < second }
- 短参数写法:在使用短参数时,参数名和关键词 in 都可以省略
numberArr.sort { $0 < $1 }
可选类型 Optional
// num可以存储 数字/空 两个状态
let num: Int? = 1
- 强行读取
!
:绝对确定变量中有包裹值的情况下,才可以使用强行读取值的感叹号。
var username: String? = "小王"
print(username!)
- 判断后读取
if username != b {
let safelyUnwrappedUsername = username!
print("\(safelyUnwrappedUsername),想听点什么")
}
- if let 语法:自动判断包裹值是否为空,若不为空则赋给新的常量适用,并执行花括号里面的代码。新的常量仅在当前花括号内存在。
if let safelyUnwrappedUsername = username {
print("\(safelyUnwrappedUsername),想听点什么")
}
- guard let 语法:该语法创建的常量可在父级别内的花括号内使用
func guardDemo() {
guard let safelyUnwrappedUsername = username else{
print("username = nil")
return
}
print("\(safelyUnwrappedUsername),想听点什么")
}
- 为可选类型增加默认值
??
var username = nil;
print("\(username ?? "你好"), 想听点什么?")
用「结构」创建自定义类型
- 基本的 struct
struct Player {
static var allPlayers: [Player] = []
var name: String
var livesRemaining = 5 {
willSet {
print("警告 还剩下\(newValue) 条命")
}
didSet {
if livesRemaining != 0 {
print("已满血复活")
} else {
print("游戏结束")
}
}
}
let maxHealth = 100
lazy var currentHealth = maxHealth
var isPlayerOutOfLives: Bool {
get {
livesRemaining == 0 ? true : false
}
set {
if newValue {
livesRemaining = 0
}
}
}
init(name: String) {
self.name = name ;
}
init(name: String, livesRemaining: Int, currentHealth: Int){
self.name = name
self.livesRemaining = livesRemaining
self.currentHealth = currentHealth
}
mutating func damaged(by health: Int){}
static func recentAddedPlayer() -> Player {
allPlayers[allPlayers.count - 1]
}
}
let player = Player(name: "player")
player.name
- 可变更 mutating:若方法函数需要更改属性的数值,则需要在方法的关键词 func 前加上另一个关键词 mutating
- lazy:告知编译器先忽略 lazy 关键词后的赋值语句,直接完成对该结构体剩余代码的编码。当该变量真正被需要时,再完成赋值。
let maxHealth = 100
lazy var currentHealth = maxHealth
- 属性观察器
willSet
、didSet
var a = 4 {
willSet {
newValue
}
didSet {
oldValue
}
}
- 预计算属性
get
、set
var b: Bool {
get {
// 设定b的值
}
set {
// 修改其他属性的值
newValue
}
}
- init 自定义初始化器
- 类型属性,关键词为 static。调用类型属性的语法为
结构名称.类型属性
,与其相似的还有类型方法。
struct Player{
static var allPlayers: [Player] = []
static func recentAddedPlayer() -> Player {
allPlayers[allPlayers.count - 1]
}
}
var wang = Player(name:"wang")
Player.allPlayers.append(contentsOf: [wang])
Player.recentAddedPlayer().name
将信息归类
- 枚举:
enum ...case
enum Source{
case num1
case num2
}
var a =Source.num1
switch a{
case .num1:
}
可选类型:Optional.none ,等于 nil
类class
与struc 区别:class 与struct 在内存中的存储方式不同;class 支持创建更复杂的父子关系,而struct 不支持;class 必须写明初始化器,而struct 自带默认的初始化器。
覆盖 override ;继承父类 super;
class 子类实体在同一个数组中转化为父类,以满足数组仅能存储同一类型数值的要求。判断数组中是否存在子类型的关键词是is
。判断并改变类型的语法是as?
(符合特征,则创类型变量)
for car in cars {
if car is Truck {}
if let teslaModel3 = car as? Sedan{}
}
- extension 扩展现有类型的内容,支持预计算属性、初始化器及方法,支持struct、class、enum、protocool。
extension Car {
var quckInfo: String {
"The car brand is \(brand)"
}
}
用协议建立规则
别名 typealias
- 类型分类:根据其存储性质划分为值类型 Value Type 如 struct、int,或引用类型 Reference Type 如 class;根据其是否由 swift 语言提供来划分分为基础类型 Basic Type 如 Int、Double、String,或自定义类型 Custom Type 如 enum、class、struct
- 别名允许你给现有的类型起另外一个名称。
typealias PhoneBook = [String: Int]
typealias Age = Int
用协议建立规则
协议 Protocol 表明做法,但不具体提供做什么,类似后端的Service 和 ServiceImpl 里的 Service,支持struct、class、enum
// 描述性的protocol
protocol Expressible {
var name: String { get }
init(name: String)
}
// 以下两种使用写法效果一致
struct User: Expressible{
var name: String
}
extension User: Expressible {}
属性Property:需统一使用关键词 var
,只读可改都需标明 { get set }
常见的协议类型
Equatable(可等性)、Comparable(可比性)、Hashable(可哈希性)、Identifiable(可辨识性)、Codable(可编码性)
- Equatable:
在自定义类中可比较,因为 == 不支持比较自定义类型。
若自定义类型中仅包含基础类型,则可以省略类方法 static func == (Self, Self) -> Bool
的写法
struct Todo: Equatable {
var content: String;
// ignore
static func ==(lhs:Todo,rhs:Todo)->Bool{
return lhs.content == rhs.content
}
}
- Comaprable:
extesnion Todo: Comparable {
static func < (lhs: Todo, rhs: Todo) -> Bool {}
}
- Hashable:
Hash 是将现有的数据结构通过一定预算转化为一个随机的、不可重复的、独特的值,
struct day: Hashable{}
let todoOne = day()
let todoTwo = day()
// 对于字典的key来说,其数值应该是唯一的。
let todos = [dayOne:todoOne,dayTwo:todoTwo]
- Identifiable:
可辨识性协议要求我们添加一个名为 id 的属性,该属性必须包含一个可哈希的数值,名为 id。
strcut Todo: Equatable, Identifiable {
var content: String;
var id = UUID()
}
异常处理及 App 的生命周期
fatalError()
模拟一个严重错误,让程序运行到这行代码时彻底停止。Error
代表异常协议do-try-catch
实践:
enum PasswordError: Error {
case notLongEnough
}
func validatePassword(_ password: String) throws -> Bool {
if password.count < 6{
throw PasswordError.notLongEnough
}
return true;
}
var password = "1234"
do{
try validatePassword(password)
print("pass")
} catch passwordError.notLongEnough {
print("at least 6")
}
try?
不具备添加额外代码的地方,主要用于获取该函数的返回值;try!
确信不会报错,报错直接中断程序运行
if let validated = try? validatePassword(password) {
print("passed")
} else {
print("at least 6")
}
// try! 运行函数,但彻底忽略错误
try! validatePassword(password)
生命周期
- Unattached(未读取) :应用完全没有被运行,也不存在于内存中的情况。
- Foreground Inactive(前台不活跃) :短暂的过渡状态,应用已经在屏幕上,但还不会对用户操作作出反馈。
- Foreground Active(前台活跃):运行
- Background(后台):应用存在于内存中,可以继续运行代码,并且随时准备再次使用。
- Suspended(挂起):在后台长期没有被使用,则会进入挂起状态,在此状态中,则处于挂起状态的应用随时会被系统从内存中移除来让出空间。
Task Async Await
var body: some View{
Text("Concurrency")
.task {
await truck()
}
}
func truck() async {
// 一些繁琐任务
for i in 0...<1_000_000_000{
print(i)
}
}