Swift 语言

精选 Swift 语言 常用指令与核心速查备忘单,涵盖高频用法、配置参数与实用技巧。

#入门指南

#变量 (Variable)

var score = 0  // Variable
let pi = 3.14  // Constant

var greeting = "Hello"
var numberOfToys = 8
var isMorning = true

var numberOfToys: Int = 8
numberOfToys += 1

print(numberOfToys)
// prints "9"

#Type annotations

var greeting: String = "Hello"
var numberOfToys: Int = 8
var isMorning: Bool = true
var price: Double = 8.99

#Arithmetic operators

  • + Add
  • - Subtraction
  • * Multiplication
  • / Division
  • % Remainder

var x = 0
x = 4 + 2 // x is now 6
x = 4 - 2 // x is now 2
x = 4 * 2 // x is now 8
x = 4 / 2 // x is now 2
x = 4 % 2 // x is now 0

  • += Adds and assigns sums
  • -= subtract and assign the difference
  • *= Multiplication and assignment
  • /= Divide and assign quotient
  • %= Divide and assign remainder

#Compound Assignment Operators

var numberOfDogs = 100
numberOfDogs += 1
print("There are \(numberOfDogs) Dalmatians!")

// print: There are 101 Dalmatians!
var x = 0
x = 4 + 2 // x is now 6
x = 4 - 2 // x is now 2
x = 4 * 2 // x is now 8
x = 4 / 2 // x is now 2
x = 4 % 2 // x is now 0

  • += 加并赋值
  • -= 减并赋值
  • *= 乘并赋值
  • /= 除并赋值商
  • %= 取余并赋值

复合赋值运算符

var numberOfDogs = 100
numberOfDogs += 1
print("There are \(numberOfDogs) Dalmatians!")

// print: There are 101 Dalmatians!

#字符串插值 (String interpolation)

var apples = 6
print("I have \(apples) apples!")

// print: I have 6 apples!

#多行字符串 (Multi-line string)

let myLongString = """
Swift?
This is my favorite language!
Yeah!
"""

#代码注释

// This line represents a comment in Swift.

/*
This is all commented out.
None will run!
*/

#构造元组 (Form a tuple)

let player = ("Maya", 5, 150)

print(player) // ("Maya", 5, 150)
print("\(player.0): level \(player.1), \(player.2) pts") // Maya: level 5, 150 pts

#分解元组 (Decompose tuple)

let player = (name: "Maya", level: 5)
let (currentName, curLevel) = player
print("\(currentName): level \(curLevel)")
// print: Maya: level 5

#特殊注释语法 MARK (Special comment syntax MARK)

// MARK: -view settings

MARK 可用于在导航栏显示注释分区

#特殊注释语法 TODO (Special comment syntax TODO)

// TODO: update logic to accommodate data changes

TODO 用于显示待办事项提醒

#特殊注释语法 FIXME (Special Comment Syntax FIXME)

// FIXME: Fix buggy behavior when making changes to existing entries

FIXME 用于显示需要修复事项的提醒

#变量

#变量声明 (Variable declaration)

使用 var 声明变量:

var greeting = "Hello"
var numberOfToys = 8
var isMorning = true

为清晰起见,变量声明可包含类型标注:

var greeting: String = "Hello"
var numberOfToys: Int = 8
var isMorning: Bool = true

变量可变,其值可以改变:

var numberOfToys: Int = 8
numberOfToys += 1

print(numberOfToys)
// print "9"

#常量 (Constants)

使用 let 声明常量:

let greeting = "Hello"
let numberOfToys = 8
let isMorning = true

为清晰起见,常量声明可包含类型标注:

let greeting: String = "Hello"
let numberOfToys: Int = 8
let isMorning: Bool = true

常量不可变,其值不能改变:

let numberOfToys: Int = 8
numberOfToys += 1
// Error: numberOfToys is immutable

#计算变量 get/set (Computed variables)

import Foundation

let df = DateFormatter()
df.dateFormat = "d MMMM yyyy"

guard var birth = df.date(from: "5 June 1999") else {
    print("Date is not valid")
    return
}

var age: Int {
    Calendar.current
        .dateComponents([.year],
                        from: birth,
                        to: Date()).year!
}

print(age) // 23
guard let birth2 = df.date(from: "5 June 2002") else {
    print("Date is not valid")
    return
}
birth = birth2
print(age) // 20

下例中,distanceInFeet 有 gettersetter。由于存在 settergetter 需要 关键字 get

var distanceInMeters: Float = 100

var distanceInFeet: Float {
  get {
    distanceInMeters *3.28
  }
  set(newDistance) {
    distanceInMeters = newDistance /3.28
  }
}

print(distanceInMeters) // 100.0
print(distanceInFeet)   // 328.0

distanceInFeet = 250
print(distanceInMeters) // 76.21951
print(distanceInFeet)   // 250.0

distanceInMeters = 800
print(distanceInMeters) // 800.0
print(distanceInFeet)   // 2624.0

#willSet 观察器 (willSet)

var distance = 5 {
  willSet {
    print("The distance will be set")
  }
}

distance = 10 // print: distance will be set

可在 willSet 中访问新值:

var distance = 5 {
  willSet(newDistance) {
    print("The distance will be set \(newDistance)")
  }
}

distance = 10 // print: distance will be set to 10

willSet 可在设置变量值之前执行代码

#didSet 观察器 (didSet)

var distance = 5 {
  didSet {
    print("The distance is set to \(distance)")
    print("Its old value is: \(oldValue)")
  }
}
distance = 10 // print: distance will be set to 10
              // print: its old value is: 5

#willSet 与 didSet (willSet and didSet)

var distance = 5 {
  willSet(newDistance) {
    print("The distance will be set to \(newDistance)")
  }
  didSet {
    print("The distance is set to \(distance)")
    print("Its old value is: \(oldValue)")
  }
}
distance = 10

#条件语句

#if 语句 (if statement)

var halloween = true
if halloween {
  print("Trick or treat!")
}
// print: Trick or treat!
if 5 > 3 {
  print("5 is greater than 3")
} else {
  print("5 is not more than 3")
}
// output: "5 is greater than 3"

#else 语句 (else statement)

var turbulence = false

if turbulence {
  print("Please sit down.")
} else {
  print("You are free to move around.")
}
// print: You are free to move around.

#else if 语句 (else if statement)

var weather = "rainy"
if weather == "sunny" {
  print("Get some sunscreen")
} else if weather == "rainy" {
  print("Take an umbrella")
} else if weather == "snowing" {
  print("Put on your snow boots")
} else {
  print("Invalid weather")
}
// print: take an umbrella

#比较运算符 (Comparison Operators)

5 > 1      // true
6 < 10     // true
2 >= 3     // false
3 <= 5     // true
"A" == "a" // false
"B" != "b" // true

-< 小于
-> 大于
-<= 小于等于
->= 大于等于
-== 等于 等于
-!= 不等于

#区间运算符 (Range Operators)

a...b      // numbers between a and b (including both a and b)
a..<b      // numbers between a and b (including a but excluding b)
...b      // numbers till b (including b)

-a...b 闭区间
-a..<b 半开区间
-...b 单侧区间

#三元条件运算符 (Ternary conditional operator)

var driverLicense = true

driverLicense
    ? print("driver seat") : print("passenger seat")
// print: driver's seat

#switch 语句 (switch statement)

var secondaryColor = "green"

switch secondaryColor {
  case "orange":
    print("A mixture of red and yellow")
  case "purple":
    print("A mix of red and blue")
  default:
    print("This may not be a secondary color")
}
// print: mix of blue and yellow

#switch 区间匹配 (switch statement interval matching)

let year = 1905
var artPeriod: String

switch year {
  case 1860...1885:
    artPeriod = "Impressionism"
  case 1886...1910:
    artPeriod = "Post-Impressionism"
  default:
    artPeriod = "Unknown"
}
// print: post-impressionism

#switch 复合 case (switch statement composite case)

let service = "Seamless"

switch service {
case "Uber", "Lyft":
    print("travel")
  case "DoorDash", "Seamless", "GrubHub":
    print("Restaurant delivery")
  case "Instacart", "FreshDirect":
    print("Grocery Delivery")
  default:
    print("Unknown service")
}
// print: restaurant takeaway

#switch where 子句 (switch statement where clause)

let num = 7

switch num {
  case let x where x % 2 == 0:
    print("\(num) is even")
  case let x where x % 2 == 1:
    print("\(num) odd number")
  default:
    print("\(num) is invalid")
}

// print: 7 odd

#逻辑运算符 (Logical Operators)

!true  // false
!false //true

#逻辑运算符 && (Logical Operators &&)

true && true   // true
true && false  // false
false && true  // false
false && false // false

#逻辑运算符 || (Logical operators ||)

true || true   // true
true || false  // true
false || true  // true
false || false // false

#组合逻辑运算符 (Combined Logical Operators)

!false && true || false // true

!false && true 先求值并返回 true,接着表达式 true || false 求值并返回 最终结果为 true

false || true && false // false

true && false 先求值返回 false,接着表达式 false || false 求值并返回 最终结果为 false

#控制执行顺序 (Control the order of execution)


// without parentheses:
true || true && false || false
//----> true

// with brackets:
(true || true) && (false || false)
//----> false

#简单 guard (Simple guards)

func greet(name: String?) {
  guard let unwrapped = name else {
    print("Hello guest!")
    return
  }
  print("Hello \(unwrapped)!")
}
greet(name: "Asma") // output: Hello Asma!
greet(name: nil)    // output: Hello guest!

#循环

#作用域 (scope)

let zeroToThree = 0...3
//zeroToThree: 0, 1, 2, 3

#stride() 函数 (stride function)

for oddNum in stride(from: 1, to: 5, by: 2) {
  print(oddNum)
}
// print: 1
// print: 3

#for-in 循环 (for-in loop)

for char in "hehe" {
  print(char)
}
// print: h
// print: e
// print: h
// print: e

#continue 关键字 (continue keyword)

for num in 0...5 {
  if num % 2 == 0 {
    continue
  }
  print(num)
}
// print: 1
// print: 3
// print: 5

continue 关键字会强制循环进入下一次迭代

#break 关键字 (break keyword)

for char in "supercalifragilistic" {
if char == "c" {
    break
  }
  print(char)
}
// print: s
// print: u
// print: p
// print: e
// print: r

#使用下划线 (Use underscores)

for _ in 1...3 {
  print("Ole")
}
// print: Ole
// print: Ole
// print: Ole

#while 循环 (while loop)

var counter = 1
var stopNum = Int.random(in: 1...10)

while counter < stopNum {
  print(counter)
  counter += 1
}
// loop to print until the stop condition is met

while 循环接受一个条件,并在条件为 true 时持续执行循环体。若 条件永不变为 false,循环会一直运行,程序将陷入 infinite loop(无限循环)

#数组和集合

#数组 (Array)

var scores = [Int]()
// array is empty: []

#.count 属性 (.count property)

var grocery = ["🥓", "🥞", "🍪", "🥛", "🍊"]
print(grocery.count)
// print: 5

#索引 (index)

索引表示有序列表中元素的位置,使用 下标语法 array[index] 取出单个元素。

var vowels = ["a", "e", "i", "o", "u"]

print(vowels[0]) // prints: a
print(vowels[1]) // prints: e
print(vowels[2]) // print: i
print(vowels[3]) // prints: o
print(vowels[4]) // prints: u

注意:Swift 数组从零开始索引,即第一个元素的索引为 0。

#用数组字面量初始化 (Initialize with array literal)

// use type inference:
var snowfall = [2.4, 3.6, 3.4, 1.8, 0.0]
// explicit type:
var temp: [Int] = [33, 31, 30, 38, 44]

#用默认值初始化 (Initialize with 默认值)

var teams = [Int](repeating: 0, count: 3)
print(teams) // prints: [0, 0, 0]
// or with Array type
var sizes = Array<Int>(repeating: 0, count: 3)
print(sizes) // prints: [0, 0, 0]

#.append() 方法与 += 运算符 (.append and +=)

var gymBadges = ["Boulder", "Cascade"]
gymBadges.append("Thunder")
gymBadges += ["Rainbow", "Soul"]
// ["Boulder", "Cascade", "Thunder",
// "Rainbow", "Soul"]

#.insert() 与 .remove() 方法 (.insert and .remove)

var moon = ["🌖", "🌗", "🌘", "🌑"]
moon.insert("🌕", at: 0)
// ["🌕", "🌖", "🌗", "🌘", "🌑"]

moon.remove(at: 4)
// ["🌕", "🌖", "🌗", "🌘"]

#遍历数组 (Iterate over an array)

var employees = ["Peter", "Denial", "Jame"]
for person in employees {
  print(person)
}
// print: Peter
// print: Denial
// print: Jam

#集合 Set (Collection Set)

var paintingsInMOMA: Set = [
  "The Dream",
  "The Starry Night",
  "The False Mirror"
]

可用集合(Set)存储相同数据类型的 unique(唯一)元素

#空集合 Set (Empty collection Set)

var team = Set<String>()

print(team)
// print: []

#填充集合 (Populate the collection)

var vowels: Set = ["a", "e", "i", "o","u"]

要创建带初始值的集合,在赋值运算符前使用 Set 关键字。

#.insert() 插入 (.insert)

var cookieJar: Set = [
  "Chocolate Chip",
  "Oatmeal Raisin"
]
// add a new element
cookieJar.insert("Peanut Butter Chip")

#.remove() 与 .removeAll() 方法 (.remove and .removeAll)

var oddNumbers: Set = [1, 2, 3, 5]

// remove existing element
oddNumbers.remove(2)
// remove all elements
oddNumbers.removeAll()

#.contains() 包含 (.contains)

var names: Set = ["Rosa", "Doug", "Waldo"]
print(names.contains("Lola")) // print: false

if names.contains("Waldo"){
  print("There's Waldo!")
} else {
  print("Where's Waldo?")
}
// print: There's Waldo!

#.isEmpty 属性 (.isEmpty property)

var emptyList = [String]()
print(emptyList.isEmpty)     // print: true

var populatedList: [Int] = [1, 2, 3]
print(populatedList.isEmpty) // print: false

#遍历集合 (Iterate over a collection)

var recipe: Set = ["Egg", "Flour", "Sugar"]

for ingredient in recipe {
  print ("Include \(ingredient) in the recipe")
}

#.isEmpty 属性 (.isEmpty property)

var emptySet = Set<String>()
print(emptySet.isEmpty)     // print: true

var populatedSet: Set = [1, 2, 3]
print(populatedSet.isEmpty) // print: false

#.count 属性 (.count property)

var band: Set = ["Peter", "Denial", "Jame"]

print("The band has \(band.count) players.")
// print: Band has 4 players.

#.intersection() 交集 (.intersection)

var setA: Set = ["A", "B", "C", "D"]
var setB: Set = ["C", "D", "E", "F"]

var setC = setA.intersection(setB)
print(setC) // print: ["D", "C"]

#.union() 并集 (.union)

var setA: Set = ["A", "B", "C", "D"]
var setB: Set = ["C", "D", "E", "F"]

var setC = setA.union(setB)
print(setC)
// print: ["B", "A", "D", "F", "C", "E"]

#.symmetricDifference() 对称差 (.symmetricDifference)

var setA: Set = ["A", "B", "C", "D"]
var setB: Set = ["C", "D", "E", "F"]

var setC = setA.symmetricDifference(setB)
print(setC)
// print: ["B", "E", "F", "A"]

#.subtracting() 差集 (.subtracting)

var setA: Set = ["A", "B", "C", "D"]
var setB: Set = ["C", "D"]

var setC = setA.subtracting(setB)
print(setC)
// print: ["B", "A"]

#字典

#基础字典 (Base Dictionary)

var dictionaryName = [
  "Key1": "Value1",
  "Key2": "Value2",
  "Key3": "Value3"
]

由数据对或键值对组成的 unordered(无序)集合

#键 (Keys)

var fruitStand = [
  "Coconuts": 12,
  "Pineapples": 12,
  "Papaya": 12
]

每个 key 都是 unique(唯一)的,即使它们包含相同的 value

#类型一致性 (Type Consistency)

var numberOfSides = [
  "triangle": 3,
  "square": 4,
  "rectangle": 4
]

仅包含 String 键与 Int

#初始化并填充字典 (Initialize and populate the dictionary)

var employeeID = [
  "Hamlet": 1367,
  "Horatio": 8261,
  "Ophelia": 9318
]

#初始化空字典 (Initialize an empty dictionary)

// initializer syntax:
var yearlyFishPopulation = [Int: Int]()

// Empty dictionary literal syntax:
var yearlyBirdPopulation: [Int: Int] = [:]

#向字典添加 (add to dictionary)

var pronunciation = [
  "library": "lai·breh·ree",
  "apple": "a·pl"
]
// new key: "programming", new value: "prow gra"
pronunciation["programming"] = "prow·gra"

#删除键值对 (Delete key-value pair)

var bookShelf = [
  "Goodnight": "Margaret Wise Brown",
  "The BFG": "Roald Dahl",
  "Falling Up": "Shel Silverstein",
  "No, David!": "David Shannon"
]
// remove value by setting key to nil
bookShelf["The BFG"] = nil

// remove value using .removeValue()
bookShelf.removeValue(forKey: "Goodnight")

// remove all values
bookShelf.removeAll()

#修改键值对 (Modify the key-value pair)

var change = [
  "Quarter": 0.29,
  "Dime": 0.15,
  "Nickel": 0.05
]

// Change the value using subscript syntax
change["Quarter"] = .25

// Change the value using .updateValue()
change.updateValue(.10, forKey: "Dime")

要修改键值对的值,可使用 .updateValue() 方法,或通过在字典名后追加方括号 [ ] 并写入已有键,再接赋值运算符 (= ) 与 修改后的值

#.isEmpty 属性 (.isEmpty property)

var bakery = [String:Int]()

// check if the dictionary is empty
print(bakery.isEmpty) // prints true
bakery["Cupcakes"] = 12
// check if the dictionary is empty
print(bakery.isEmpty) // print false

#.count 属性 (.count property)

var fruitStand = [
  "Apples": 12,
  "Oranges", 17
]
print(fruitStand.count) // print: 2

#将值赋给变量 (Assigning values to variables)

var hex = [
  "red": "#ff0000",
  "yellow": "#ffff00",
  "blue": "#0000ff",
]

print("Blue hexadecimal code \(hex["blue"])")
// print: blue hex code 可选("#0000ff")

if let redHex = hex["red"] {
  print("red hexadecimal code \(redHex)")
}
// print: red hex code #ff0000

将键值对的值赋给变量会返回 可选 值。要提取值,请使用 可选 展开

#遍历字典 (Traversing the dictionary)

var emojiMeaning = [
  "🤔": "Thinking Face",
  "😪": "Sleepy Face",
  "😵": "Dizzy Face"
]
// loop through keys and values
for (emoji, meaning) in emojiMeaning {
  print("\(emoji) is called '\(meaning)Emoji'")
}
// iterate through keys only
for emoji in emojiMeaning.keys {
  print(emoji)
}
// iterate through values only
for meaning in emojiMeaning.values {
  print(meaning)
}

#函数

#基本函数 (Basic functions)

func washCar() -> Void {
  print("Soap")
  print("Scrub")
  print("Rinse")
  print("Dry")
}

#调用函数 (Call functions)

func greetLearner() {
 print("Welcome to qr.warpnav.com!")
}
// function call:
greetLearner()
// print: Welcome to qr.warpnav.com!

#返回值 (return value)

let birthYear = 1994
var currentYear = 2020

func findAge() -> Int {
  return currentYear-birthYear
}

print(findAge()) // prints: 26

#多参数 (Multiple parameters)

func convertFracToDec(numerator: Double, denominator: Double) -> Double {
  return numerator / denominator
}

let decimal = convertFracToDec(numerator: 1.0, denominator: 2.0)
print(decimal) // prints: 0.5

#省略参数标签 (Omit parameter labels)

func findDiff(_ a: Int, b: Int) -> Int {
  return a -b
}

print(findDiff(6, b: 4)) // prints: 2

#返回多个值 (return multiple values)

func smartphoneModel() -> (name: String, version: String, yearReleased: Int) {
  return ("iPhone", "8 Plus", 2017)
}
let phone = smartphoneModel()

print(phone.name)         // print: iPhone
print(phone.version)      // print: 8 Plus
print(phone.yearReleased) // print: 2017

#参数与实参 (Parameters & Arguments)

func findSquarePerimet(side: Int) -> Int {
  return side *4
}

let perimeter = findSquarePerimet(side: 5)
print(perimeter) // print: 20

// Parameter: side
// Argument: 5

#隐式返回 (Implicit return)

func nextTotalSolarEclipse() -> String {
  "April 8th, 2024 🌎"
}

print(nextTotalSolarEclipse())
// print: April 8th, 2024 🌎

#默认参数 (Default parameters)

func greet(person: String = "guest") {
  print("Hello \(person)")
}
greet() // Hello guest
greet(person: "Aliya") // Hello Aliya

#输入输出参数 (Input and output parameters)

var currentSeason = "Winter"

func season(month: Int, name: inout String) {
  switch month {
    case 1...2:
      name = "Winter ⛄️"
    case 3...6:
      name = "Spring 🌱"
    case 7...9:
      name = "Summer ⛱"
    case 10...11:
      name = "Autumn 🍂"
    default:
      name = "Unknown"
  }
}
season(month: 4, name: &currentSeason)

print(currentSeason) // Spring 🌱

#可变参数 (variable parameter)

func totalStudent(data: String...) -> Int {
  let numStudents = data.count
  return numStudents
}

print(totalStudent(data: "Denial", "Peter"))
// print: 2

#可选参数 (可选 parameters)

func getFirstInitial(from name: String?) -> String? {
  return name?.first
}

函数可接受并返回 可选 类型。当函数无法返回所请求类型的合理实例 时,应返回 nil

#结构体

#结构体创建 (Structure Creation)

struct Building {
  var address: String
  var floors: Int
  init(address: String, floors: Int) {
    self.address = address
    self.floors = floors
  }
}

结构体用于在代码中程序化表示现实对象。使用 struct 关键字,后跟名称,再跟包含属性与方法的主体

#默认属性值 (Default property values)

struct Car {
  var numOfWheels = 4
  var topSpeed = 80
}

var reliantRobin = Car(numOfWheels: 3)

print(reliantRobin.numOfWheels) // prints: 3
print(reliantRobin.topSpeed)    // print: 80

#结构体实例创建 (Structural instance creation)

struct Person {
  var name: String
  var age: Int

  init(name: String, age: Int) {
    self.name = name
    self.age = age
  }
}

// Person instance:
var morty = Person(name: "Peter", age: 14)

#init() 方法 (init method)

struct TV {
  var size: Int
  var type: String

  init(size: Int, type: String) {
    self.size = size
    self.type = type
  }
}

使用 TV

var newTV = TV(size: 65, type: "LED")

#检查类型 (Check type)

print(type(of: "abc")) // print: String
print(type(of: 123))   // print: 123

#变异方法 mutating (Mutation method)

struct Menu {
  var menuItems = ["Fries", "Burgers"]
  mutating func addToMenu(dish: String) {
    self.menuItems.append(dish)
  }
}

使用 Menu

var dinerMenu = Menu()
dinerMenu.addToMenu(dish: "Toast")
print(dinerMenu.menuItems)
// prints: ["Fries", "Burgers", "Toast"]

#结构体方法 (Structural methods)

struct Dog {
  func bark() {
    print("Woof")
  }
}
let fido = Dog()
fido.bark() // prints: Woof

#

#引用类型 class (reference type class)

class Player {
  var name: String

  init(name: String) {
    self.name = name
  }
}

var player1 = Player(name: "Tomoko")
var player2 = player1
player2.name = "Isabella"

print(player1.name) // Isabella
print(player2.name) // Isabella

#类的实例 (instance of the class)

class Person {
  var name = ""
  var age = 0
}

var sonny = Person()
// sonny is now an instance of Person

#init() 方法 (init method)

class Fruit {
  var hasSeeds = true
  var color: String

  init(color: String) {
    self.color = color
  }
}

使用 Fruit 类

let apple = Fruit(color: "red")

类可通过 init() 方法及相应初始化属性进行初始化。在 init() 方法中,使用 self 关键字引用正在赋属性值的类实例

#类属性 (Class Attributes)

var ferris = Student()

ferris.name = "Ferris Bueller"
ferris.year = 12
ferris.gpa = 3.81
ferris.honors = false

#继承 (Inherit)

假设有一个 BankAccount 类:

class BankAccount {
  var balance = 0.0
  func deposit(amount: Double) {
    balance += amount
  }
  func withdraw(amount: Double) {
    balance -= amount
  }
}

SavingsAccount 继承 BankAccount

class SavingsAccount: BankAccount {
  var interest = 0.0

  func addInterest() {
    let interest = balance *0.005
    self.deposit(amount: interest)
  }
}

新的 SavingsAccount 类(子类)自动获得 BankAccount 类 (超类)的全部特性。此外,SavingsAccount 还定义了 .interest 属性与 .addInterest() 方法。

#示例 (Example)

使用数据类型

class Student {
  var name: String
  var year: Int
  var gpa: Double
  var honors: Bool
}

使用默认属性值

class Student {
  var name = ""
  var gpa = 0.0
  var honors = false
}

#结构体与类定义示例 (struct and class definition example)

struct Resolution {
  var width = 0
  var height = 0
}
class VideoMode {
  var resolution = Resolution()
  var interlaced = false
  var frameRate = 0.0
  var name: String?
}

Resolution 结构体定义与 VideoMode 类定义仅描述 ResolutionVideoMode,创建结构体或类的实例:

let resolution = Resolution(width: 1920)
let someVideoMode = VideoMode()

#枚举

#定义枚举 (Define the enumeration)

enum Day {
  case monday
  case tuesday
  case wednesday
  case thursday
  case friday
  case saturday
  case sunday
}

let casualWorkday: Day = .friday

#Switch 语句 (Switch statement)

enum Dessert {
  case cake(flavor: String)
  case vanillaIceCream(scoops: Int)
  case brownie
}

let customerOrder: Dessert = .cake(flavor: "Red Velvet")
switch customerOrder {
  case let .cake(flavor):
    print("You ordered a \(flavor) cake")
  case .brownie:
    print("You ordered a chocolate cake")
}
// prints: "You ordered a red velvet cake"

#CaseIterable 协议 (CaseIterable)

enum Season: CaseIterable {
  case winter
  case spring
  case summer
  case falls
}

for season in Season.allCases {
  print(season)
}

遵循 CaseIterable 协议即可访问 allCases 属性,它返回枚举全部 case 的数组 该枚举

#原始值 (Original value)

enum Beatle: String {
  case john paul george ringo
}

print("The Beatles are \(Beatle.john.rawValue).")
// print: The Beatles are john.
enum Dessert {
  case cake(flavor: String)
  case vanillaIceCream(scoops: Int)
  case brownie
}

let order: Dessert = .cake(flavor: "Red Velvet")

#实例方法 (instance method)

enum Traffic {
  case light
  case heavy

  mutating func reportAccident() {
    self = .heavy
  }
}

var currentTraffic: Traffic = .light

currentTraffic.reportAccident()
// currentTraffic is now .heavy

与类和结构体一样,枚举也可有实例方法。若实例方法会修改 枚举,则需标记为 mutating

#从原始值初始化 (Initialize from primitive value)

enum Hello: String {
  case english = "Hello"
  case japanese = "Hello!"
  case emoji = "👋"
}
let hello1 = Hello(rawValue: "Hello!")
let hello2 = Hello(rawValue: "Привет")
print(hello1) // 可选(Hello.japanese)
print(hello2) // nil

#计算属性 (Computed properties)

enum ShirtSize: String {
  case small = "S"
  case medium = "M"
  case large = "L"
  case extraLarge = "XL"
  var description: String {
    return "The size of this shirt is \(self.rawValue)"
  }
}

#扩展

#什么是扩展 (What are extensions?)

扩展用于为已有的类、结构体、枚举或协议类型添加新功能。 包括添加新方法、属性、初始化器等。

#为何使用扩展 (Why use extensions?)

扩展特别适合在不修改原始类型的情况下组织与模块化代码, 尤其是在无法访问原始源代码时。

#扩展语法 (Extension syntax)

extension SomeType {
    // New functionalities to be added
}

#计算属性 (Computed properties)

extension Int {
    var isEven: Bool {
        self % 2 == 0
    }
}

print(4.isEven) // Outputs: true
print(7.isEven) // Outputs: false

#方法 (Methods)

extension String {
    func reverse() -> String {
        String(self.reversed())
    }
}

print("abc".reverse()) // Output: cba

#变异方法 (Mutating methods)

extension Int {
    mutating func square() {
        self = self * self
    }
}

var number = 5
number.square()
print(number) // Output: 25

#初始化器 (Initializers)

extension Date {
    init?(timestamp: Double) {
        self.init(timeIntervalSince1970: timestamp)
    }
}

let timestamp = 1693982400.0 // Unix timestamp for 2023-09-06 06:40:00
if let date = Date(timestamp: timestamp) {
    print(date) // Output: 2023-09-06 06:40:00 +0000
}

#下标 (Subscripts)

extension String {
    subscript(index: Int) -> Character {
        self[self.index(startIndex, offsetBy: index)]
    }
}

print("Swift"[0]) // Output: S
print("Swift"[1]) // Output: w
print("Swift"[2]) // Output: i
print("Swift"[3]) // Output: f
print("Swift"[4]) // Output: t

#协议扩展 (Protocol extensions)

就“希望某功能在所有类中都可用”而言,它很像抽象类: 实现某协议的所有类中可用(无需继承公共基类)。

// Define a protocol
protocol Describable {
    func describe() -> String
}

// Provide a default implementation using a protocol extension
extension Describable {
    func describe() -> String {
        "This is a generic description"
    }
}

// Define a struct that conforms Describable protocol
struct Person: Describable {
    var name: String
    var age: Int

    // Overriding the default implementation
    func describe() -> String {
        "My name is \(name) and I am \(age) years old."
    }
}

struct Employee: Describable {
    var name: String
    var age: Int

    // Using the default implementation
}

// By just implementing the protocol the describe() method is available

let person = Person(name: "Ivan", age: 21)
let employee = Employee(name: "Saul", age: 25)

print(person.describe()) // Output: My name is Ivan and I am 21 years old.
print(employee.describe()) // Output: This is a generic description

#扩展约束 (Constraints for extensions)

当我们想为遵循特定协议或满足 某些条件时特别有用。

extension Array where Element: Numeric {
    func sum() -> Element {
        reduce(0, +)
    }
}

let numbers = [1, 2, 3, 4, 5]
print(numbers.sum()) // Output: 15

let doubles = [1.5, 2.5, 3.5]
print(doubles.sum()) // Output: 7.5

// This will not work because String is not Numeric
// let strings = ["a", "b", "c"]
// print(strings.sum()) // Error: Cannot invoke 'sum' with an array of strings

#用扩展组织代码 (Organizing code with extensions)

扩展不限于添加功能,也便于组织代码。我们可以把相关的 方法、属性或视图到不同的扩展中。

import SwiftUI

struct HomeView: View {
    var body: some View {
        ScrollView {
            header
            // Add other views
        }
    }
}

extension HomeView {
    private var header: some View {
        Text("Header ...")
    }
}

#Preview {
    HomeView()
}

#泛型

#什么是泛型 (What are generics?)

Swift 泛型允许我们创建可与任意数据类型协作的函数、类、结构体和协议。 与任意数据类型一起使用。

#为何使用泛型 (Why use generics?)

泛型让我们写出清晰简洁、适用于任意数据类型的代码。通过使用占位符(如 T),这 降低引入缺陷的风险。

#类型参数 (Type parameters)

func foo<T, U>(a: T, b: U) {
  // ...
}

struct Foo<T, U> {
  var a: T
  // ...
}

占位符 T 是类型参数示例,写在尖括号中(如 <T>)。

#泛型数据结构 (Generic Data Structures)

struct Box<T> {
    var value: T
}
let intBox = Box(value: 10)
let stringBox = Box(value: "Hello")

print(intBox.value) // Output: 10
print(stringBox.value) // Output: "Hello"

#泛型函数 (Generic Functions)

func swapValues<T>(_ a: inout T, _ b: inout T) {
    let temp = a
    a = b
    b = temp
}

var a = 10
var b = 20
swapValues(&a, &b)
print(a) // Output: 20
print(b) // Output: 10

var c = "Hello"
var d = "World"
swapValues(&c, &d)
print(c) // Output: "World"
print(d) // Output: "Hello"

#泛型约束 (Constraints on Generics)

func sum<T: Numeric>(_ array: [T]) -> T {
    array.reduce(0, +)
}

print(sum([1, 1.5, 2])) // Output: 4.5

// This will not work because String is not Numeric
// print(sum(["a", "b", "c"]))
// Error: function 'sum' requires that 'String' conform to 'Numeric'

#关联类型 (Associated Types)

protocol Foo {
    associatedtype T
    func foo() -> T
}

关联类型用于在协议中定义稍后指定的类型占位符,充当 泛型占位符。具体类型不在协议中定义,而是在类、结构体 或枚举遵循该协议时再确定。

#泛型协议 (Generic Protocols)

protocol Storage {
    associatedtype Item
    func store(item: Item)
    func retrieve() -> Item?
}

class SimpleStorage<T>: Storage {
    private var items: [T] = []

    func store(item: T) {
        items.append(item)
    }

    func retrieve() -> T? {
        return items.isEmpty ? nil : items.removeLast()
    }
}

let intStorage = SimpleStorage<Int>()
intStorage.store(item: 42)
print(intStorage.retrieve() ?? "Empty")  // Output: 42

#泛型类型别名 (Generic Typealiases)

泛型类型别名可为已有类型创建新名称(即不会引入新类型)。

typealias StringDictionary<T> = [String: T]
typealias IntFunction<T> = (Int) -> Int
typealias Vector<T> = (T, T, T)

#🔗 参考资源