阅读 2563

Swift 5.1 极简参考手册

本文由 漫慢忙 翻译自 raywenderlich 教程 Swift 5.1 Cheat Sheet and Quick Reference ,请参考原文阅读

声明常量和变量

• 使用 let 关键字声明一个常量

let double: Double = 2.0
// double = 3.0 // 错误:不能给常量重新赋值
let inferredDouble = 2.0 // 推断为一个 Double 类型
复制代码

• 使用 var 关键字声明一个变量

var mutableInt: Int = 1
mutableInt = 2 // OK: 可以给一个变量重新赋值
复制代码

数值类型转换

let integerValue = 8
let doubleValue = 8.0
//let sum = integerValue + double // 错误:类型不匹配
复制代码

• 使用显式的方法来防止隐藏的转换错误并有助于明确类型转换意图

let sum = Double(integerValue) + double // OK: 两个值有相同类型
复制代码

字符串

• 使用字符串字面量来初始化一个常量或变量

let helloWorld = "Hello, World!"
复制代码

• 使用多行字符串字面量来跨越多行

let helloWorldProgram = """
A "Hello, World!" program generally is a computer program
that outputs or displays the message "Hello, World!"
"""
复制代码

• 空字符串

let emptyString = "" // 使用字符串字面量
let anotherEmptyString = String() // 初始化语法
复制代码

• 修改字符串

var mutableString = "Swift"
mutableString += " is awesome!"
复制代码

• 字符串插值

print("The value is \(double)") // 插入一个 Double 值
print("This is my opinion: \(mutableString)") // 插入一个字符串
复制代码

元组

• 将多个值组合为一个复合值

let httpError = (503, "Server Error")
复制代码

• 分解元组的内容

let (code, reason) = httpError

// 另一种分解方式
let codeByIndex = httpError.0
let reasonByIndex = httpError.1
复制代码

• 使用 _ 来忽略元组的某些部分

let (_, justTheReason) = httpError
复制代码

可选项

• catchphrase 可以包含 String 或 nil

var catchphrase: String? // 由编译器自动设置为nil
catchphrase = "Hey, what's up, everybody?"
复制代码

• 强制解包操作符 (!)

// 如果 catchphrase 不是nil,count1 包含 catchphrase 的计数值;
// 否则程序崩溃
let count1: Int = catchphrase!.count
复制代码

• 可选绑定

// 如果 catchphrase?.count 返回的可选 Int 包含一个值,
// 则将一个称为 count 的新常量设置为可选中包含的值
if let count = catchphrase?.count {
  print(count)
}
复制代码

• 合并操作符(??)

// 如果 catchphrase 不是 nil,count2 包含 catchphrase 的 count 值; 否则为 0
let count2: Int = catchphrase?.count ?? 0
复制代码

• 链式操作符(?)

// 如果 catchphrase 不是nil,count3 包含 catchphrase 的 count 值; 否则为 nil
let count3: Int? = catchphrase?.count
复制代码

• 隐式展开的可选值

let forcedCatchphrase: String! = "Hey, what's up, everybody?"
let implicitCatchphrase = forcedCatchphrase // 无需使用感叹号
复制代码

集合类型:Array

let immutableArray: [String] = ["Alice", "Bob"]
// mutableArray 的类型为 [String]
var mutableArray = ["Eve", "Frank"]
复制代码

• 测试包含关系

let isEveThere = immutableArray.contains("Eve")
let name: String = immutableArray[0] // 通过索引访问
复制代码

• 在列表中修改项目

// 如果索引越界,则崩溃
mutableArray[1] = "Bart"
// immutableArray[1] = "Bart" // 错误:不能修改
mutableArray.append("Ellen") // 添加项目
mutableArray.insert("Gemma", at: 1) // 在指定索引处添加项目

// 不能重新赋值一个常量集合或修改它的内容
// 可以重新赋值一个可变集合和修改它的w内容
mutableArray = ["Ilary", "David"]
mutableArray[0] = "John"
复制代码

• 通过索引来删除

let removedPerson = mutableArray.remove(at: 1)
复制代码

集合类型: Dictionary

let immutableDict: [String: String] = ["name": "Kirk", "rank": "captain"]
// mutableDict 的类型为 [String: String]
var mutableDict = ["name": "Picard", "rank": "captain"]
复制代码

• 通过 key 来访问,如果不存在对应的 key,则返回 nil

let name2: String? = immutableDict["name"]
复制代码

• 更新 key 对应的 value

mutableDict["name"] = "Janeway"
复制代码

• 添加新的 key-value

mutableDict["ship"] = "Voyager"
复制代码

• 通过 key 来删除项目,如果 key 不存在,则返回 nil

let rankWasRemoved: String? = mutableDict.removeValue(forKey: "rank")
复制代码

集合类型: Set

• Set 会忽略重复项,所以 immutableSet 只有 2 项:"chocolate" 和 "vanilla"

let immutableSet: Set = ["chocolate", "vanilla", "chocolate"]
var mutableSet: Set = ["butterscotch", "strawberry"]
复制代码

• 测试包含关系

immutableSet.contains("chocolate")
复制代码

• 添加项目

mutableSet.insert("green tea")
复制代码

• 移除项目,如果没有找到项目,则返回 nil

let flavorWasRemoved: String? = mutableSet.remove("strawberry")
复制代码

控制流:循环

• 遍历一个列表或集合

//for item in listOrSet {
//    print(item)
//}
复制代码

• 遍历字典

//for (key, value) in dictionary {
//    print("\(key) = \(value)")
//}
复制代码

• 遍历范围

// 闭区间操作符(...)
for i in 0...10 {
  print(i) // 0 to 10
}
// 半开区间操作符(..<)
for i in 0..<10 {
  print(i) // 0 to 9
}
复制代码

• while

var x = 0
while x < 10 {
  x += 1
  print(x)
}
复制代码

• repeat-while

repeat {
  x -= 1
  print(x)
} while(x > 0)
复制代码

控制流:条件语句

• 使用 if 来选择不同路径

let number = 88
if (number <= 10) {
  // 如果 number <= 10, 则执行这里
} else if (number > 10 && number < 100) {
  // 如果 number > 10 && number < 100, 则执行这里
} else {
  // 否则执行这里
}
复制代码

• 三元操作符

// if-else条件的简写
let height = 100
let isTall = height > 200 ? true : false
复制代码

• 如果不满足一个或多个条件,请使用 guard 将程序控制权转移出一个范围

for n in 1...30 {
  guard n % 2 == 0 else {
    continue
  }
  print("\(n) is even")
}
复制代码

• 使用 switch 来选择不同路径

let year = 2012
switch year {
case 2003, 2004:
  // 如果 year 是 2003 或者 2004,则执行这个语句
  print("Panther or Tiger")
case 2010:
  // 如果 year 的值是 2010,则执行这个语句
  print("Lion")
case 2012...2015:
  // 如果 year 在 2012-2015 范围内(包含边界值),则执行这个语句
  print("Mountain Lion through El Captain")
default: // 每个 switch 语句必须涵盖所有情况
  print("Not already classified")
}
复制代码

函数

• 返回 Void 的函数

func sayHello() {
  print("Hello")
}
复制代码

• 带参数的函数

func sayHello(name: String) {
  print("Hello \(name)!")
}
复制代码

• 带默认参数值的函数

//func sayHello(name: String = "Lorenzo") {
//  print("Hello \(name)!")
//}
复制代码

• 混合默认值的参数和常规参数的函数

//func sayHello(name: String = "Lorenzo", age: Int) {
//  print("\(name) is \(age) years old!")
//}
//
//sayHello(age: 35) // 只使用非默认值参数调用
复制代码

• 带参数和返回值的函数

func add(x: Int, y: Int) -> Int {
  return x + y
}
let value = add(x: 8, y: 10)
复制代码

• 如果函数只有一个表达式,则可以省略 return

func multiply(x: Int, y: Int) -> Int {
  x + y
}
复制代码

• 指定参数的 label

//func add(x xVal: Int, y yVal: Int) -> Int {
//  return xVal + yVal
//}
复制代码

• 省略一些参数的参数 label

//func add(_ x: Int, y: Int) -> Int {
//    return x + y
//}
//let value = add(8, y: 10)
复制代码

• 接受函数作为参数的函数

func doMath(operation: (Int, Int) -> Int, a: Int, b: Int) -> Int {
  return operation(a, b)
}
复制代码

闭包

let adder: (Int, Int) -> Int = { (x, y) in x + y }
复制代码

• 带有速记参数名的闭包

let square: (Int) -> Int = { $0 * $0 }
复制代码

• 将一个闭包传递给函数

let addWithClosure = doMath(operation: adder, a: 2, b: 3)
复制代码

枚举

enum Taste {
  case sweet, sour, salty, bitter, umami
}
let vinegarTaste = Taste.sour
复制代码

• 迭代枚举

enum Food: CaseIterable {
  case pasta, pizza, hamburger
}

for food in Food.allCases {
  print(food)
}
复制代码

• 带有 String 原始值的枚举

enum Currency: String {
  case euro = "EUR"
  case dollar = "USD"
  case pound = "GBP"
}
复制代码

• 打印原始值

let euroSymbol = Currency.euro.rawValue
print("The currency symbol for Euro is \(euroSymbol)")
复制代码

• 带有关联值的枚举

enum Content {
  case empty
  case text(String)
  case number(Int)
}
复制代码

• 使用 switch 语句来匹配枚举值

let content = Content.text("Hello")
switch content {
case .empty:
  print("Value is empty")
case .text(let value): // 提取 String 值
  print("Value is \(value)")
case .number(_): // 忽略 Int 值
  print("Value is a number")
}
复制代码

结构体

struct User {
  var name: String
  var age: Int = 40
}
复制代码

• 结构体自动创建一个逐一构造器,该构造器接收与所有属性匹配的参数

let john = User(name: "John", age: 35)
复制代码

• 如果属性有初始值,逐一构造器会将其作为默认参数值

let dave = User(name: "Dave")
复制代码

• 访问属性

print("\(john.name) is \(john.age) years old")
复制代码

class Person {
  let name: String
  // 类构造器
  init(name: String) {
    self.name = name
  }
  
  // 使用 deinit 来执行对象资源清理操作
  deinit {
    print("Perform the deinitialization")
  }
  
  var numberOfLaughs: Int = 0
  func laugh() {
    numberOfLaughs += 1
  }
  
  // 定义一个计算属性
  var isHappy: Bool {
    return numberOfLaughs > 0
  }
}

let david = Person(name: "David")
david.laugh()
let happy = david.isHappy
复制代码

• 继承

class Student: Person {
  var numberOfExams: Int = 0
  
  // 重写 isHappy 计算属性,以提供额外逻辑
  override var isHappy: Bool {
    numberOfLaughs > 0 && numberOfExams > 2
  }
}

let ray = Student(name: "Ray")
ray.numberOfExams = 4
ray.laugh()
//let happy = ray.isHappy
复制代码

• 用 final 来标记 Child,以阻止其被继承

final class Child: Person { }
复制代码

• 指定构造器和便捷构造器

// 一个类需要至少一个指定构造器
// 同时可以有一个或多个便捷构造器
class ModeOfTransportation {
  let name: String
  // 定义一个指定构造器
  // 其携带一个名为 name 的参数
  init(name: String) {
    self.name = name
  }
  
  // 定义一个便捷构造器
  // 没有携带参数
  convenience init() {
    // 委托给内部指定构造器
    self.init(name: "Not classified")
  }
}

class Vehicle: ModeOfTransportation {
  let wheels: Int
  // 定义一个指定构造器
  // 带有两个参数
  init(name: String, wheels: Int) {
    self.wheels = wheels
    // 委托给父类指定构造器
    super.init(name: name)
  }
  
  // 重写父类便捷构造器
  override convenience init(name: String) {
    // 委托给内部指定构造器
    self.init(name: name, wheels: 4)
  }
}
复制代码

扩展

• 扩展可以给已存在的类、结构体、枚举或协议类型添加新的功能

extension String {
  // 扩展 String 类型来计算一个 String 实例是真还是假
  var boolValue: Bool {
    if self == "1" {
      return true
    }
    return false
  }
}

let isTrue = "0".boolValue
复制代码

错误处理

• 表示一个错误

enum BeverageMachineError: Error {
  case invalidSelection
  case insufficientFunds
  case outOfStock
}

func selectBeverage(_ selection: Int) throws -> String {
  // Some logic here
  return "Waiting for beverage..."
}
复制代码

• 如果在 do 代码块中抛出一个异常,它会与catch子句匹配,以确定其中哪一个可以处理错误

let message: String
do {
  message = try selectBeverage(20)
} catch BeverageMachineError.invalidSelection {
  print("Invalid selection")
} catch BeverageMachineError.insufficientFunds {
  print("Insufficient funds")
} catch BeverageMachineError.outOfStock {
  print("Out of stock")
} catch {
  print("Generic error")
}
复制代码

• 如果在 try? 语句中抛出一个错误,则表达式的值为 nil

let nillableMessage = try? selectBeverage(10)
复制代码

• 如果抛出一个异常,则会导致运行时错误;否则获取返回值

let throwableMessage = try! selectBeverage(10)
复制代码

访问控制

• 一个模块(framework 或 application)是一个独立的代码分发单元,可以在其它模块中通过 import 关键字来导入

public class AccessLevelsShowcase { // 可以从其它模块中访问类
  public var somePublicProperty = 0 // 可以从其它模块中访问该属性
  var someInternalProperty = 0 // 可以在包含该类的块中访问该属性
  fileprivate func someFilePrivateMethod() {} // 可以从定义该类的源文件中访问该属性
  private func somePrivateMethod() {} // 可以在该类的代码块中访问该属性
}
复制代码

协议

• Codable 和 Decodable/Encodable 两个协议的组合是一样的

import Foundation
struct UserInfo: Codable {
  let username: String
  let loginCount: Int
}
复制代码

• 实现 CustomStringConvertible 协议来提供将实例转换化字符串时的描述信息

extension UserInfo: CustomStringConvertible {
  var description: String {
    return "\(username) has tried to login \(loginCount) time(s)"
  }
}
复制代码

• 定义一个表达 JSON 的多行字符串

let json = """
{ "username": "David", "loginCount": 2 }
"""
复制代码

• 使用 JSONDecoder 来序列化一个 JSON

let decoder = JSONDecoder()
复制代码

• 将字符串转化为 UserInfo 实例

let data = json.data(using: .utf8)!
let userInfo = try! decoder.decode(UserInfo.self, from: data)
print(userInfo)
复制代码

• 使用 Encodable 来序列化一个结构体

let encoder = JSONEncoder()
let userInfoData = try! encoder.encode(userInfo)
复制代码

• 将 UserInfo 实例转换为字符串表示

let jsonString = String(data: userInfoData, encoding: .utf8)!
print(jsonString)
复制代码

更多好文,请关注公众号 "知识小集" (ID: zsxjtip)

关注下面的标签,发现更多相似文章
评论