Swift 快速上手
变量
/* 常量 */
let MAX = 100
let MIN = 1
/* 变量 */
var count = 0
/* 带类型标注 */
let name: String = "张三"
var age: Int = 18
/* 多变量声明 */
var x = 0.0, y = 0.0, z = 0.0
/* 类型推断 */
/* String */
var message = "Hello, Swift!"
/* 可空类型 */
var optionalName: String? = nil
流程控制
IF
if age >= 18 {
print("成年人")
} else {
print("未成年人")
}
if count < MIN {
print("count 小于 MIN")
}
else if count == MIN {
print("count 等于 MIN")
}
else if count >= 5 {
print("count 大于等于 5")
}
else if count <= 10 {
print("count 小于等于 10")
}
else if count != 11 {
print("count 不等于 11")
}
else if count > MAX {
print("count 大于 MAX")
}
if name == "张三" && age == 18 {
print("张三是18岁")
}
if name == "李四" || age == 20 {
print("名字是李四或者年龄是20")
}
if !(name == "张三") {
print("名字不是张三")
}
Switch
switch count {
case MIN:
print("count 等于 MIN")
case 5...10:
print("count 大于等于 5 小于等于 10")
case 11:
print("count 等于 11")
case let n where n % 2 == 0:
print("count 是偶数")
case 12, 13, 14:
print("count 是 12, 13, 14 中的一个")
default:
print("其他情况")
}
守卫语句
if let unwrappedName = optionalName {
/* 值仅在此花括号内有效 */
print("可选值有值:\(unwrappedName)")
} else {
/* 无值处理 */
print("可选值为空")
}
guard let unwrappedName = optionalName else {
/* 无值处理 需要中断执行 否则后续代码会继续执行 */
print("可选值为空")
return
}
/* 值在 guard 后的花括号剩余范围中有效 */
print("可选值有值:\(unwrappedName)")
循环
/* [1, 5] */
for i in 1...5 {
print(i)
}
/* [0, 5) */
for i in 0..<5 {
print(i)
}
/* [0, 5] */
for i in ...5 {
print(i)
}
/* 步长为2 不包含结束值 */
for n in stride(from: 1, to: 5, by: 2) {
print(n)
}
/* 步长为2 包含结束值 */
for n in stride(from: 1, through: 5, by: 2) {
print(n)
}
/* 遍历字符串字符 */
for c in "Hello Swift" {
print(c) // 'H'、'e'、...
}
/* 忽略循环变量 */
for _ in 1...3 {
print("Hello")
}
/* 跳过循环 */
for n in 0...100 {
if n % 2 == 0 {
continue
}
print(n)
}
/* 提前退出循环 */
for n in 1...10 {
if n == 5 {
break
}
print(n)
}
/* 无限循环 */
while true {
print("无限循环")
}
/* 有限循环 */
while count < 10 {
count += 1
print(count)
}
/* 至少执行一次 */
repeat {
count -= 1
print(count)
} while count > 0
函数
/* 基本函数 */
func printHello() {
print("Hello, Swift!")
}
printHello()
/* 带参数函数 */
func printHello(name: String) {
print("Hello, \(name)!")
}
printHello("World")
/* 带返回值函数 */
func getPrintContent() -> String {
return "Hello, Swift!"
}
print(getPrintContent())
/* 带参数和隐式返回值函数 */
func getLogContent(name: String) -> String {
"Hello, \(name)!"
}
print(getLogContent("World"))
/* 带多个参数函数 */
func add(a: Int, b: Int) -> Int {
a + b
}
print(add(a: 5, b: 10))
/* 带多个返回值函数 */
func getAddResult(a: Int, b: Int) -> (Int, Int, Int) {
return (a, b, a + b)
}
let addResult = getAddResult(a: 5, b: 10)
print("\(addResult.0) + \(addResult.1) = \(addResult.2)")
/* 带命名返回值函数 */
func getAddData(a: Int, b: Int) -> (first: Int, second: Int, sum: Int) {
return (a, b, a + b)
}
let addData = getAddData(a: 5, b: 10)
print("\(addData.first) + \(addData.second) = \(addData.sum)")
/* 带别名参数函数 */
func go(from p1: Int, to p2: Int) {
for i in p1...p2 {
print("from \(p1) to \(p2) current in \(i)")
}
}
go(from: 1, to: 5)
/* 可变参数函数 */
func addNumbers(_ numbers: Int...) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
print(addNumbers(1, 2, 3, 4, 5))
/* 带输入输出参数函数 */
var sesason = "Spring"
func nextSeason(_ season: inout String) {
switch season {
case "Spring":
season = "Summer"
case "Summer":
season = "Autumn"
case "Autumn":
season = "Winter"
case "Winter":
season = "Spring"
default:
season = "Unknown"
}
}
print("当前季节:\(sesason)")
nextSeason(&sesason)
print("下一个季节:\(sesason)")
/* 可选参数与可空返回值函数 */
func getFirst(name: String?) -> String? {
return name?.first
}
if let firstChar = getFirst(name: "张三") {
print("名字的第一个字是:\(firstChar)")
} else {
print("名字为空")
}
/* 函数作为参数 */
func computed(
a: Int,
b: Int,
operate: (Int, Int) -> Int
) -> Int {
return operate(a, b)
}
var sum = -1
/* 标准函数参数 */
sum = computed(a: 5, b: 10, operate: { (x: Int, y: Int) -> Int in
return x + y
})
/* 当最后一个参数是函数时,允许尾随闭包 */
sum = computed(a: 5, b: 10) { (x: Int, y: Int) -> Int in
return x + y
}
/* 自动推断类型 */
sum = computed(a: 5, b: 10, operate: { (x, y) in
x + y
})
/* 简化参数,$0、$1 分别代表第一个和第二个输入参数,后续其他参数以此类推 */
sum = computed(a: 5, b: 10, operate: { $0 + $1 })
print("5 + 10 = \(sum)")
/* 函数闭包 */
func addNumber(_ n: Int) -> (Int) -> (Int) -> Int {
func addInner(_ m: Int) -> (Int) -> Int {
func addFinal(_ p: Int) -> Int {
return n + m + p
}
return addFinal
}
return addInner
}
let add1 = addNumber(1)
let add2 = add1(2)
print(add2(3)) // 1 + 2 + 3 = 6
泛型
/* 交换 int 元组 */
func swapIntTuple(_ tuple: (Int, Int)) -> (Int, Int) {
return (tuple.1, tuple.0)
}
/* 交换 double 元组 */
func swapDoubleTuple(_ tuple: (Double, Double)) -> (Double, Double) {
return (tuple.1, tuple.0)
}
/* 交换元组而不在乎类型 */
func swapGenericTuple<T>(_ tuple: (T, T)) -> (T, T) {
return (tuple.1, tuple.0)
}
/* 两个数值类型相加 将 N 类型约束为 Numberic 数字类型 */
func add<N: Numeric>(_ a: N, _ b: N) -> N {
a + b
}
/* 返回值隐藏类型,但对编译器已知 */
func getView() -> some Numeric {
// 等价于 func getView<ReturnValueType>() -> ReturnValueType where ReturnValueType: Numeric
2
}
结构体
/* 结构体是值类型 */
struct Person<V> {
var name: String
/* 结构体默认值 */
var age: Int = 0
/* 延迟属性 在首次访问时才创建 */
lazy var bigData = Array(repeating: 0, count: 1000)
/* 计算属性 根据其他值计算出而不是存储值 */
var msg: String { return "name: \(name)\nage: \(age)" }
/* 接收泛型 */
var data: [[V]] = []
/* 定义下标访问 */
subscript(row: Int, col: Int) -> V {
get { return data[row][col] }
set { data[row][col] = newValue }
}
/* 嵌套内部类型 */
struct Children {
var name: String
}
/* 结构体构造函数 */
init(_ name: String) {
self.name = name
}
/* 结构体方法 */
func say(_ msg: String) -> Void {
print("\(self.name) say \(msg)")
}
/* 结构体变异方法 修改结构体属性 */
mutating func nextAge() -> Int {
self.age += 1
return self.age
}
/* 结构体变异方法 修改结构体自身 */
mutating func changePerson(_ name: String) -> Self {
self = Person(name)
return self
}
}
类
/* 类是引用类型 */
class Person<V> {
var name: String
/* 内部类默认值 */
var age: Int = 0
/* 接收泛型 */
var data: [V] = []
/* 类构造函数 */
init(name: String) {
self.name = name
}
/* 便利构造器 简化初始逻辑 */
convenience init(name: String, age: Int){
self.init(name: name)
self.age = age
}
/* 属性观察器 */
var score: Int = 0 {
willSet { print("Score 将变为 \(newValue)") }
didSet { print("Score 先前是 \(oldValue)") }
}
/* 下标 */
subscript(index: Int) -> V? {
return index >= 0 && index < data.count ? data[index] : nil
}
/* 静态属性 */
static var count: Int = 0
/* 静态方法 */
static func setCounter(){
count += 1
}
/* 析构函数 */
deinit{
print("\(name)被释放")
}
}
/* 类继承 */
class Father {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
func info() -> String {
return "name: \(name), age: \(age)"
}
/* 不允许被重写 */
final func say() {
print("hello")
}
}
/* 子类 final 不允许再继承了 */
final class Son: Father {
var school: String
init(name: String, age: Int, school: String) {
self.school = school
super.init(name: name, age: age)
}
/* 重写父类方法 */
override func info() -> String {
return super.info() + ", school: \(school)"
}
}
class Node {
/* 父节点强引用子节点 */
var children: Node?
/* 子节点弱引用父节点 避免循环引用 */
weak var parent: Node?
}
枚举
enum Day {
/* 枚举值会自动增加 */
case sunday = 0
case monday // 1
case tuesday // 2
case wednesday // 3
case thursday // 4
case friday // 5
case saturday // 6
}
/* 在确定类型的情况下 可以省略类型名 直接使用 .xxx 语法 */
let casualWorkday: Day = .friday // 等价于 Day.friday
/* 从原始值初始化 */
enum Direction: String {
case north = "N"
case south = "S"
case east = "E"
case west = "W"
}
let direction1 = Direction(rawValue: "N") // Optional(Direction.north)
let direction2 = Direction(rawValue: "X") // nil
let north = Direction.north.rawValue // "N"
/* 关联值枚举 */
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check):
print("UPC: \(numberSystem), \(manufacturer), \(product), \(check)")
case .qrCode(let code):
print("QR Code: \(code)")
}
/* 计算属性 */
enum Power {
case NONE = 0
case READ = 4
case WRITE = 2
case EXECUTE = 1
var name: String {
switch self {
case .NONE: return "none"
case .READ: return "read"
case .WRITE: return "write"
case .EXECUTE: return "execute"
}
}
}
/* 可迭代 */
/* CaseIterable 是一个迭代协议,允许访问 allCases 获取枚举所有值数组 */
enum Season: CaseIterable {
case winter
case spring
case summer
case fall
}
for season in Season.allCases {
print(season)
}
/* 实例方法 */
enum Traffic {
case light
case heavy
/* 变异方法 允许改变枚举实例值,需要使用 mutating 标记 */
mutating func reportAccident() {
self = .heavy
}
}
var currentTraffic: Traffic = .light
currentTraffic.reportAccident()
协议
/* 协议类似抽象类 但允许被类、结构体、枚举等实现 */
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
class SimpleClass: ExampleProtocol {
var simpleDescription: String = "A very simple class."
var anotherProperty: Int = 69105
func adjust() {
simpleDescription += " Now 100% adjusted."
}
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription
struct SimpleStructure: ExampleProtocol {
var simpleDescription: String = "A simple structure"
mutating func adjust() {
simpleDescription += " (adjusted)"
}
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription
扩展
/* 扩展可以为以现有的类、结构体、枚举或协议增加新的属性和方法 */
extension Int {
// 扩展 Int 实现新功能
}
extension Int: ExampleProtocol {
// 扩展 Int 实现 ExampleProtocol 协议
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self += 42
}
}
extension ExampleProtocol {
func adjust(){
// 扩展协议,进行默认实现
}
}
错误处理
/* 任何实现了 Error 协议的枚举都被视为错误 */
enum PrinterError: Error {
case outOfPaper
case noToner
case onFire
}
/* 函数可以使用 throws 关键字标记,表明它可能会抛出错误 */
func send(job: Int, toPrinter printerName: String) throws -> String {
if printerName == "Never Has Toner" {
throw PrinterError.noToner
}
return "Job sent"
}
do {
let response = try send(job: 1040, toPrinter: "Test")
print(response)
}
/* 统一处理错误 */
catch {
print(error)
}
do {
let response = try send(job: 1040, toPrinter: "Test")
print(response)
}
catch PrinterError.onFire {
// 单独处理某个错误
}
catch let e as PrinterError {
// 处理 .onFire 以外的所有 PrinterError 枚举错误
}
/* 统一处理错误 */
catch {
print(error)
}
/* 将结果转换为可选的 如果错误发生,则会被抛弃,结果变为 nil */
let success = try? send(job: 1884, toPrinter: "Mergenthaler")
/* 退出前执行 无论是否抛出错误 */
func executeTask() {
print("执行任务开始")
defer {
print("任务结束,进行清理工作")
}
print("处理中...")
}
executeTask()
异步
/* async 用于标记异步函数 */
func fetch(from server: String) async -> Int {
if server == "http://localhost" {
return 200
}
return 500
}
/* 在异步函数前使用 await 关键字调用 按定义顺序依次执行 */
func fetchUsername(from server: String) async -> String {
let fetchURL = await fetch(from: server)
let userID = await fetch(from: fetchURL)
if userID == 500 {
return "John Appleseed"
}
return "Guest"
}
/* 使用 async let 会让多个异步任务并发执行 而不是按定义顺序依次执行 但在函数执行完毕退出时,必须 await 所有 async let */
func fetchLogin(account: String, pwd: String) async -> String {
async let loginReq = fetch(from: "http://localhost/login?account=\(account)&pwd=\(pwd)")
async let userIDReq = fetch(from: "http://localhost/userID?account=\(account)")
let userID = await userIDReq
async let usernameReq = fetchUsername(from: "http://localhost/username?userID=\(userID)")
let login = await loginReq
let username = await usernameReq
return "loginResult: \(login), userIDResult: \(userID), usernameResult: \(username)"
}
模块化
Project/
|- Package.swift
|- Sources/
|- Network/
|- Request.swift
|- Response.swift
|- PreHandle.swift
|- lastHandle.swift
|- UI/
|- HomeView.swift
|- LoginView.swift
|- Model/
|- User.swift
|- Article.swift
|- APP/
|- main.swift
// Package.swift
import PackageDescription
let package = Package(
name: "Project",
platforms: [.iOS(.v15)],
products: [
.executable(name: "App", targets: ["App"])
],
targets: [
.target(name: "Model"),
.target(name: "Network", dependencies: ["Model"]),
.target(name: "UI", dependencies: ["Network"]),
.executableTarget(name: "App", dependencies: ["UI"])
]
)
// App → UI → Network -> Model
// 扩模块暴露 可继承重写
open class Person {}
// 跨模块暴露 不可继承重写
public struct User {}
// 仅在当前模块内暴露 默认
internal class LoginService {}
// 仅当前文件暴露
fileprivate struct LoginDTO {}
// 仅当前作用域暴露
private var n: String
Swift 快速上手
https://www.inksha.com/archives/swift-kuai-su-shang-shou