// 定义变量和常量, 自动推导类型
var myVariable = 42
let myConstant = 42
// 指定类型
let implicitInteger = 70
let implicitDouble = 70.0
let explicitDouble: Double = 70
// 不支持隐式类型转换, 需要显示转换
let label = "The width is "
let width = 94
let widthLabel = label + String(width)
// 类型后面加上`?`, 标记这个值是可选的. 可以包含一个值或者nil
var optionalString: String? = "Hello"
var red, green, blue: Double
var a = 1, b = 2, c = 3
// 支持UTF-8 标识符
let 🐶🐮 = "dogcow"
let cat = "🐱"; print(cat)
// UInt8, Int8, Uint16, Int16, Uint32, Int32, UInt64, Int64
// Int: 32位平台, 默认Int32; 64位平台, 默认Int64
// UInt: 32位平台, 默认UInt32; 64位平台, 默认UInt64
let minValue = UInt8.min // minValue is equal to 0, and is of type UInt8
let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8
// Double 64位 默认, 15位小数
// Float 32位, 6位小数
var a = 0.1
let decimalInteger = 17
let binaryInteger = 0b10001 // 17 in binary notation
let octalInteger = 0o21 // 17 in octal notation
let hexadecimalInteger = 0x11 // 17 in hexadecimal notation
let decimalDouble = 12.1875
let exponentDouble = 1.21875e1
let hexadecimalDouble = 0xC.3p0
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1
// Type Aliases
typealias AudioSample = UInt16
// Tuples
let http404Error = (404, "Not Found") // compound
let (statusCode, statusMessage) = http404Error // decompose
let (justTheStatusCode, _) = http404Error
print("The status code is \(http404Error.0)")
print("The status message is \(http404Error.1)")
let http200Status = (statusCode: 200, description: "OK")
print("The status code is \(http200Status.statusCode)")
// = 不会返回值, 只有赋值操作. 所以不会与== 弄混
// 0..<10 [0, 10); 0...10 [0, 10]; names[2...] or names[...2] or names[..<2]
// 支持 一元, 二元, 三元操作
// 赋值
let b = 10
var a = 5
a = b
let (x, y) = (1, 2)
// 一元: +, -
let b = -1
// 二元
1 + 2
5 - 3
2 * 3
10.0 / 2.5
"hello, " + "world"
9 % 4
// 复合赋值运算符
var a = 1
a += 2
// 三元
a = bo ? a : b
a = bo ? b
// 逻辑操作
Equal to (a == b)
Not equal to (a != b)
Greater than (a > b)
Less than (a < b)
Greater than or equal to (a >= b)
Less than or equal to (a <= b)
Logical NOT (!a)
Logical AND (a && b)
Logical OR (a || b)
// 两个同长度, 同类型的tuples 可以比较. 从左到右 直到找到不相等的值
(1, "zebra") < (2, "apple")
// Nil-Coalescing Operator 空合并操作
a = a ?? b 相当于 a != nil ? a! : b
1. 不会隐匿转换, 编译时会类型检查
2. Optionals 类型, 当类型转换时返回可选类型
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
if convertedNumber != nil {
print("convertedNumber contains some integer value.")
}
if let constantName = someOptional {
statements
}
let possibleString: String? // 可选类型
let assumedString: String! // 隐式解包, 当确定可选值有值, 并且一直会有值
// 模板字符串
let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit."
// 多行字符串
let quotation = """
I said "I have \(apples) apples."
And then I said "I have \(apples + oranges) pieces of fruit."
"""
// 多行字符串, 有前导空格会在字符串中忽略, 非前导空格会加到字符串
// 特殊字符使用`\`转义
// 支持unicode
let dollarSign = "\u{24}"
// Characters
for character in "Dog!🐶" {
print(character)
}
let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"]
// `#` 扩展字符串分隔符
let str1 = #"Line 1\nLine 2"#
相当于
let str2 = "Line 1\\nLine 2"
let str3 = ###"Line1\###nLine2"###
相当于
let str4 = "Line1\nLine2"
// String Interpolation
let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
let greeting = "Guten Tag!"
greeting[greeting.startIndex]
// G
greeting[greeting.index(before: greeting.endIndex)]
// !
greeting[greeting.index(after: greeting.startIndex)]
// u
let index = greeting.index(greeting.startIndex, offsetBy: 7)
greeting[index]
// a
var welcome = "hello"
welcome.insert("!", at: welcome.endIndex)
welcome.insert(contentsOf: " there", at: welcome.index(before: welcome.endIndex))
welcome.remove(at: welcome.index(before: welcome.endIndex))
let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex
welcome.removeSubrange(range)
// substrings
let greeting = "Hello, world!"
let index = greeting.firstIndex(of: ",") ?? greeting.endIndex
let beginning = greeting[..<index]
let newString = String(beginning)
hasPrefix(_:)
hasSuffix(_:)
// 字符串的 Unicode 表示
A collection of UTF-8 code units (accessed with the string’s utf8 property)
A collection of UTF-16 code units (accessed with the string’s utf16 property)
A collection of 21-bit Unicode scalar values, equivalent to the string’s UTF-32 encoding form (accessed with the string’s unicodeScalars property)
// 创建空数组或者字典
let emptyArray: [String] = []
let emptyDictionary: [String: Float] = [:]
// Array
var arr : [Int] = [] // 可变的
let arr : [Int] = [] // 不可变的
var threeDoubles = Array(repeating: 0.0, count: 3)
var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
var sixDoubles = threeDoubles + anotherThreeDoubles
var shoppingList: [String] = ["Eggs", "Milk"]
print("The shopping list contains \(shoppingList.count) items.")
if shoppingList.isEmpty {
print("The shopping list is empty.")
} else {
print("The shopping list isn't empty.")
}
shoppingList.append("Flour")
shoppingList += ["Baking Powder"]
shoppingList[4...6] = ["Bananas", "Apples"]
shoppingList.insert("Maple Syrup", at: 0)
let apples = shoppingList.removeLast()
for item in shoppingList {
print(item)
}
for (index, value) in shoppingList.enumerated() {
print("Item \(index + 1): \(value)")
}
// Set
var letters = Set<Character>()
letters.insert("a")
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
if let removedGenre = favoriteGenres.remove("Rock") {
print("\(removedGenre)? I'm over it.")
} else {
print("I never much cared for that.")
}
a.intersecion(b) // 交集
a.symmetricDifference(b) // 非交集
a.union(b) // 并集
a.subtracting(b) // a - b
Use the intersection(_:) method to create a new set with only the values common to both sets.
Use the symmetricDifference(_:) method to create a new set with values in either set, but not both.
Use the union(_:) method to create a new set with all of the values in both sets.
Use the subtracting(_:) method to create a new set with values not in the specified set.
Use the “is equal” operator (==) to determine whether two sets contain all of the same values.
Use the isSubset(of:) method to determine whether all of the values of a set are contained in the specified set.
Use the isSuperset(of:) method to determine whether a set contains all of the values in a specified set.
Use the isStrictSubset(of:) or isStrictSuperset(of:) methods to determine whether a set is a subset or superset, but not equal to, a specified set.
Use the isDisjoint(with:) method to determine whether two sets have no values in common.
// Dictionaries
var namesOfIntegers: [Int: String] = [:]
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
airports["LHR"] = "London"
if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
print("The old value for DUB was \(oldValue).")
}
if let removedValue = airports.removeValue(forKey: "DUB") {
print("The removed airport's name is \(removedValue).")
} else {
print("The airports dictionary doesn't contain a value for DUB.")
}
// Iterating Over a dictionary
for (airportCode, airportName) in airports {
print("\(airportCode): \(airportName)")
}
for airportCode in airports.keys {
print("Airport code: \(airportCode)")
}
for airportName in airports.values {
print("Airport name: \(airportName)")
}
let airportCodes = [String](airports.keys)
let airportNames = [String](airports.values)
// 条件或者循环中的括号是可选的
if a == b {}
// if 语句条件必须是Boolean表达式, 不会隐式转换数值
if (1) {} //是错误的
// if + let 语句可以处理可能为nil的值
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \(name)"
}
// 使用`??`也可以处理可选值
let nickname: String? = nil
let fullName: String = "John Appleseed"
let informalGreeting = "Hi \(nickname ?? fullName)"
// swift 支持任何类型和任何比较, swift不是贯通的
let vegetable = "red pepper"
switch vegetable {
case "celery":
print("Add some raisins and make ants on a log.")
case "cucumber", "watercress":
print("That would make a good tea sandwich.")
case let x where x.hasSuffix("pepper"):
print("Is it a spicy \(x)?")
default:
print("Everything tastes good in soup.")
}
// 使用区间
let approximateCount = 62
let countedThings = "moons orbiting Saturn"
let naturalCount: String
switch approximateCount {
case 0:
naturalCount = "no"
case 1..<5:
naturalCount = "a few"
case 5..<12:
naturalCount = "several"
case 12..<100:
naturalCount = "dozens of"
case 100..<1000:
naturalCount = "hundreds of"
default:
naturalCount = "many"
}
// 使用tuples
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
print("\(somePoint) is at the origin")
case (_, 0):
print("\(somePoint) is on the x-axis")
case (0, _):
print("\(somePoint) is on the y-axis")
case (-2...2, -2...2):
print("\(somePoint) is inside the box")
default:
print("\(somePoint) is outside of the box")
}
// 值绑定
let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
print("on the x-axis with an x value of \(x)")
case (0, let y):
print("on the y-axis with a y value of \(y)")
case let (x, y):
print("somewhere else at (\(x), \(y))")
}
// where
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
print("(\(x), \(y)) is just some arbitrary point")
}
// 复合案例
let someCharacter: Character = "e"
switch someCharacter {
case "a", "e", "i", "o", "u":
print("\(someCharacter) is a vowel")
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
"n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
print("\(someCharacter) is a consonant")
default:
print("\(someCharacter) isn't a vowel or a consonant")
}
// 使用`for - in`迭代序列, array/dictionary
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
var largest = 0
for (_, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
}
}
}
// 使用`while`或者`repeat while`来重复一段代码, 直到条件到达
var n = 2
while n < 100 {
n *= 2
}
var m = 2
repeat {
m *= 2
} while m < 100
// 可以使用range
var total = 0
for i in 0..<4 {
total += i
}
// tuple 元组
let a : (min: Int, max: Int, sum: Int) = (1, 2, 3)
// 流程跳转
continue
break
fallthrough
return
throw
// 标记语句 Labeled statements
label name: while condition {
statements
}
break <label name>
// 提前退出
guard let name = person["name"] else {
return
}
// 检查API版本
if #available(iOS 10, macOS 10.12, *) {
// Use iOS 10 APIs on iOS, and use macOS 10.12 APIs on macOS
} else {
// Fall back to earlier iOS and macOS APIs
}
if #available(platform name version, ..., *) {
statements to execute if the APIs are available
} else {
fallback statements to execute if the APIs are unavailable
}
// `func`定义函数, `->` 指定返回类型
func greet(person: String, day: String) -> String {
return "Hello \(person), today is \(day)."
}
greet(person: "Bob", day: "Tuesday")
// 通常使用参数名称来传递参数, 可以使用`_`指定参数可以不使用参数名称
func greet(_ person: String, on day: String) -> String {
return "Hello \(person), today is \(day)."
}
greet("John", on: "Wednesday")
// 返回值可以是元组
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
var min = scores[0]
var max = scores[0]
var sum = 0
for score in scores {
if score > max {
max = score
} else if score < min {
min = score
}
sum += score
}
return (min, max, sum)
}
// Functions With an Implicit return
func greeting(for person: String) -> String {
"Hello, " + person + "!"
}
// Function Argument Labels and Parameter Names
func someFunction(argumentLabel parameterName: Int) {
// In the function body, parameterName refers to the argument value
// for that parameter.
}
// Omitting Argument Labels
func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
// In the function body, firstParameterName and secondParameterName
// refer to the argument values for the first and second parameters.
}
// Default Parameter Values
func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
// If you omit the second argument when calling this function, then
// the value of parameterWithDefault is 12 inside the function body.
}
// Variadic Parameters
func arithmeticMean(_ numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
// In-Out Parameters, 默认参数是常量, 如果需要改变参数的值, 使用`inout` 关键字
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
// 函数类型
var mathFunction: (Int, Int) -> Int = addTwoInts
// 闭包: 函数可以嵌套, 内部函数可以访问外部函数的变量; 函数是一级对象, 函数可以返回另一个函数
func returnFifteen() -> ((Int) -> Int) {
var y = 10
func add(num: Int) -> Int {
num += 5
return num;
}
y = add(y)
return add
}
// 一个函数可以做为另一个函数的参数
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
for item in list {
if condition(item) {
return true
}
}
return false
}
func lessThanTen(number: Int) -> Bool {
return number < 10
}
var numbers = [20, 19, 7, 12]
hasAnyMatches(list: numbers, condition: lessThanTen)
// 创建匿名闭包`({})`
{ (parameters) -> return type in
statements
}
numbers.map({ (number: Int) -> Int in
let result = 3 * number
return result
})
// 当闭包参数类型已知, 返回类型已知, 那么可以忽略参数和返回类型
let mappedNumbers = numbers.map({ number in 3 * number })
print(mappedNumbers)
// 当闭包很简短, 那么可以用下标访问参数, 如果闭包是唯一参数, 那么`()`可以忽略
let sortedNumbers = numbers.sorted { $0 > $1 }
print(sortedNumbers)
// Operator Methods
reversedNames = names.sorted(by: >)
// @noescape @escaping @autoclosure
@noescape 已弃用, 默认. 只在函数内使用, 函数结束后, 闭包生命周期结束
@escaping 可以在函数生命周期外使用, 闭包一般在函数结束后调用
@autoclosure 默认@escaping, 不接收参数, 自动将表达式转换成闭包
// 当对象为常量(let)时, 不能调用mutating 方法, 因为他不可变
// Assigning to self Within a Mutating Method
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
self = Point(x: x + deltaX, y: y + deltaY)
}
}
// `class` 修改对象方法, 可以成为类型方法, 类型方法里的self指向类型本身
class SomeClass {
class func someTypeMethod() {
// type method implementation goes here
}
}
SomeClass.someTypeMethod()
根类
weak
弱引用; Unowned
无主引用支持嵌套类型
// 使用`class`创建类, 声明属性和方法跟变量和函数一样.
class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
// 创建对象, 访问属性和方法
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
// `init` 方法为构造方法, `self`代表当前对象
// `deinit` 释放对象
// `:` 指定超类(不支持多重继承), `super`引用超类, `override`重写超类方法
class Square: NamedShape {
var sideLength: Double
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 4
}
func area() -> Double {
return sideLength * sideLength
}
override func simpleDescription() -> String {
return "A square with sides of length \(sideLength)."
}
}
// override 可以重写方法和属性, 使用`final` 防止重写
// 属性`lazy`, 当第一次访问时初始化, 支持全局常量和变量
// 只有getter方法, 没有setter就是只读属性
// `propertyWrapper`, 属性getter, setter包装器
@propertyWrapper
struct TwelveOrLess {
private var number = 0
var wrappedValue: Int {
get { return number }
set { number = min(newValue, 12) }
}
}
struct SmallRectangle {
@TwelveOrLess var height: Int
@TwelveOrLess var width: Int
}
// `projectedValue` 映射值, 在属性前加上`$`引用映射值
@propertyWrapper
struct SmallNumber {
private var number: Int
private(set) var projectedValue: Bool
var wrappedValue: Int {
get { return number }
set {
if newValue > 12 {
number = 12
projectedValue = true
} else {
number = newValue
projectedValue = false
}
}
}
init() {
self.number = 0
self.projectedValue = false
}
}
struct SomeStructure {
@SmallNumber var someNumber: Int
}
var someStructure = SomeStructure()
someStructure.someNumber = 4
print(someStructure.$someNumber)
// 属性可以有`getter`和`setter`方法, `newValue` 当setter被调用时, 传进来的值隐式名称
class EquilateralTriangle: NamedShape {
var sideLength: Double = 0.0
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 3
}
var perimeter: Double {
get {
return 3.0 * sideLength
}
set {
sideLength = newValue / 3.0
}
}
override func simpleDescription() -> String {
return "An equilateral triangle with sides of length \(sideLength)."
}
}
// 属性可以有`willSet`和`didSet`, 当值设置前和设置后调用
var triangle: EquilateralTriangle {
willSet {
square.sideLength = newValue.sideLength
}
}
// 不对象是可选类型时, 可以使用`?`调用
// Optional Chaining
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare?.sideLength
// `static` 修改属性为类型属性, 默认lazy, 只有初始化一次, 必须被初始化
// convenience init 是designed init扩展, 必须调用designed init
// `is` 和 `as` 来判断和强转类型 as? 可选项; as! 强制
// `enum`创建权举, 权举可以有自己的方法, 默认权举下标`rawValue`从0开始
// rawValue 还可以使用字符串和浮点值类型
enum Rank: Int {
case ace = 1
case two, three, four, five, six, seven, eight, nine, ten
case jack, queen, king
func simpleDescription() -> String {
switch self {
case .ace:
return "ace"
case .jack:
return "jack"
case .queen:
return "queen"
case .king:
return "king"
default:
return String(self.rawValue)
}
}
}
let ace = Rank.ace
let aceRawValue = ace.rawValue
// 遍历权举
for beverage in Beverage.allCases {
print(beverage)
}
// `init?(rawValue:)` 使用原始值匹配权举值, 不匹配返回nil
if let convertedRank = Rank(rawValue: 3) {
let threeDescription = convertedRank.simpleDescription()
}
// 只有一个rawValue值, 值和案例关联, 值是创建权举值时传入
enum ServerResponse {
case result(String, String)
case failure(String)
}
let success = ServerResponse.result("6:00 am", "8:09 pm")
let failure = ServerResponse.failure("Out of cheese.")
switch success {
case let .result(sunrise, sunset):
print("Sunrise is at \(sunrise) and sunset is at \(sunset).")
case let .failure(message):
print("Failure... \(message)")
}
// Recursive Enumerations, `indirect` 可以引用自己
enum ArithmeticExpression {
case number(Int)
indirect case addition(ArithmeticExpression, ArithmeticExpression)
indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}
indirect enum ArithmeticExpression {
case number(Int)
case addition(ArithmeticExpression, ArithmeticExpression)
case multiplication(ArithmeticExpression, ArithmeticExpression)
}
func evaluate(_ expression: ArithmeticExpression) -> Int {
switch expression {
case let .number(value):
return value
case let .addition(left, right):
return evaluate(left) + evaluate(right)
case let .multiplication(left, right):
return evaluate(left) * evaluate(right)
}
}
// `struct`创建结构, 结构也可以有属性和方法, 和类区别是copied传递, 类是引用传递
struct Card {
var rank: Rank
var suit: Suit
func simpleDescription() -> String {
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
}
}
let threeOfSpades = Card(rank: .three, suit: .spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
// Structures and Enumerations Are Value Types
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
cinema.width = 2048
cinema !== hd
// Identity Operators
Identical to (===)
Not identical to (!==)
// Access Control * public - Open access and public access enable entities to be used within any source file from their defining module, and also in a source file from another module that imports the defining module. You typically use open or public access when specifying the public interface to a framework. The difference between open and public access is described below. * internal(默认) - Internal access enables entities to be used within any source file from their defining module, but not in any source file outside of that module. You typically use internal access when defining an app’s or a framework’s internal structure. * fileprivate - File-private access restricts the use of an entity to its own defining source file. Use file-private access to hide the implementation details of a specific piece of functionality when those details are used within an entire file. * private - Private access restricts the use of an entity to the enclosing declaration, and to extensions of that declaration that are in the same file. Use private access to hide the implementation details of a specific piece of functionality when those details are used only within a single declaration.
// `subscript`, 支持任意数量入参, 支持类型方法
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
// `protocol` 定义一个协议
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
// 类, 权举, 结构都可以实现协议.
// 结构实现协议方法, 需要`mutating`修饰, 表示是可修改的; 类不用, 因为类的方法
// 都是可以修改的
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` 扩展已存在的类型, 特别用于在类型上扩展一致的协议
extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self += 42
}
}
// Extension Syntax
extension SomeType {
// new functionality to add to SomeType goes here
}
// Computed Properties
extension Double {
var km: Double { return self * 1_000.0 }
var m: Double { return self }
var cm: Double { return self / 100.0 }
var mm: Double { return self / 1_000.0 }
var ft: Double { return self / 3.28084 }
}
// Extension Initializers
extension Rect {
init(center: Point, size: Size) {
let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 2)
self.init(origin: Point(x: originX, y: originY), size: size)
}
}
// Extension Methods
extension Int {
func repetitions(task: () -> Void) {
for _ in 0..<self {
task()
}
}
}
// Extension Subscripts
extension Int {
subscript(digitIndex: Int) -> Int {
var decimalBase = 1
for _ in 0..<digitIndex {
decimalBase *= 10
}
return (self / decimalBase) % 10
}
}
// Nested Types
extension Int {
enum Kind {
case negative, zero, positive
}
var kind: Kind {
switch self {
case 0:
return .zero
case let x where x > 0:
return .positive
default:
return .negative
}
}
}
// 协议可以作为类型, 当协议作为类型时, 其他方法隐藏不可用
// Protocol Syntax
protocol SomeProtocol {
// protocol definition goes here
}
// Property Requirements; gettable settable
protocol SomeProtocol {
var mustBeSettable: Int { get set }
var doesNotNeedToBeSettable: Int { get }
}
// Method Requirements
protocol RandomNumberGenerator {
func random() -> Double
}
// Mutating Method Requirements, 允许该方法修改属性和对象
protocol Togglable {
mutating func toggle()
}
enum OnOffSwitch: Togglable {
case off, on
mutating func toggle() {
switch self {
case .off:
self = .on
case .on:
self = .off
}
}
}
// Initializer Requirements
protocol SomeProtocol {
init(someParameter: Int)
}
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
// initializer implementation goes here
}
}
// `Error` 表示错误
enum PrinterError: Error {
case outOfPaper
case noToner
case onFire
}
func canThrowAnError() throws {
// this function may or may not throw an error
}
do {
try canThrowAnError()
// no error was thrown
} catch {
// an error was thrown
}
// `throw` 抛出错误
func send(job: Int, toPrinter printerName: String) throws -> String {
if printerName == "Never Has Toner" {
throw PrinterError.noToner
}
return "Job sent"
}
// `do - catch`处理错误
do {
let printerResponse = try send(job: 1440, toPrinter: "Gutenberg")
print(printerResponse)
} catch PrinterError.onFire {
print("I'll just put this over here, with the rest of the fire.")
} catch let printerError as PrinterError {
print("Printer error: \(printerError).")
} catch {
print(error)
}
// `try?` 处理错误, 可以把返回转换成可选值, 如果有异常就返回nil
let printerSuccess = try? send(job: 1884, toPrinter: "Mergenthaler")
// try 配合do-catch, 起到传播异常的作用, try! 强制解包
// `defer` 会在return前执行, 抛出异常也会执行, 可以在设置旁边编写`defer`清理代码
func fridgeContains(_ food: String) -> Bool {
fridgeIsOpen = true
defer {
fridgeIsOpen = false
}
let result = fridgeContent.contains(food)
return result
}
// 打印错误信息并停止
fatalError(_:file:line:)
// `<Item>` 创建一个泛型
func makeArray<Item>(repeating item: Item, numberOfTimes: Int) -> [Item] {
var result: [Item] = []
for _ in 0..<numberOfTimes {
result.append(item)
}
return result
}
makeArray(repeating: "knock", numberOfTimes: 4)
// 函数, 方法, 类, 权举, 结构可以使用泛型
enum OptionalValue<Wrapped> {
case none
case some(Wrapped)
}
var possibleInteger: OptionalValue<Int> = .none
possibleInteger = .some(100)
// `where` 函数和方法body前, 指定一列表需求
func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Bool
where T.Element: Equatable, T.Element == U.Element
{
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
return true
}
}
}
return false
}
anyCommonElements([1, 2, 3], [3])
// Opaque Types `some`
// `async` 表明一个函数或方法是异步的, 写在`throws` 或者`->` 之前
func listPhotos(inGallery name: String) async throws -> [String] {
let result = // ... some asynchronous networking code ...
return result
}
// `await` 设置挂载点, 当异步方法返回或抛出异常时, 继续执行下一步
这些地方可以调用异步方法:
Code in an unstructured child task, as shown in Unstructured Concurrency below.
// downloadPhoto是异步的, 但是需要一条条的执行
let firstPhoto = await downloadPhoto(named: photoNames[0])
let secondPhoto = await downloadPhoto(named: photoNames[1])
let thirdPhoto = await downloadPhoto(named: photoNames[2])
let photos = [firstPhoto, secondPhoto, thirdPhoto]
show(photos)
// for-await-in 可以等待下一个可以项
for try await line in photos {
print(line)
}
// Parallel, 并行执行异步方法
async let firstPhoto = downloadPhoto(named: photoNames[0])
async let secondPhoto = downloadPhoto(named: photoNames[1])
async let thirdPhoto = downloadPhoto(named: photoNames[2])
let photos = await [firstPhoto, secondPhoto, thirdPhoto]
show(photos)
structured concurrency Task是异步运行的工作单元, 所有异步代码都作为Task的一部分运行. async-let 会创建一个子任务运行. Task Group是管理Task的, 添加删除, 设置数量等 任务按层次结构排列, 在同一任务组中所有任务都有同一个父任务, 任务都可以有自己的子任务.
await withTaskGroup(of: Data.self) { taskGroup in
let photoNames = await listPhotos(inGallery: "Summer Vacation")
for name in photoNames {
taskGroup.addTask { await downloadPhoto(named: name) }
}
}
使用
withTaskGroup
创建任务组, 使用addTask
添加任务
Unstructured concurrency Task.init(priority:operation:) Task.detached(priority:operation:)
任务取消:
Task.checkCancellation() 当任务已取消会抛CancellationError异常 Task.isCancelled 检查是否已经取消 Task.cancel() 手动取消
Actor
跟类一样是引用类型, 与类的区别是, 一次只准一个任务访问他的状态
// 非
let initialBits: UInt8 = 0b00001111
let invertedBits = ~initialBits // equals 11110000
// 与
let firstSixBits: UInt8 = 0b11111100
let lastSixBits: UInt8 = 0b00111111
let middleFourBits = firstSixBits & lastSixBits // equals 00111100
// 或
let someBits: UInt8 = 0b10110010
let moreBits: UInt8 = 0b01011110
let combinedbits = someBits | moreBits // equals 11111110
// 异或
let firstBits: UInt8 = 0b00010100
let otherBits: UInt8 = 0b00000101
let outputBits = firstBits ^ otherBits // equals 00010001
// 左移 右移
let shiftBits: UInt8 = 4 // 00000100 in binary
shiftBits << 1 // 00001000
shiftBits << 2 // 00010000
shiftBits << 5 // 10000000
shiftBits << 6 // 00000000
shiftBits >> 2 // 00000001
var potentialOverflow = Int16.max
potentialOverflow += 1 // this causes an Error
Overflow addition (&+) Overflow subtraction (&-) Overflow multiplication (&*)
var unsignedOverflow = UInt8.max
unsignedOverflow = unsignedOverflow &+ 1 // unsignedOverflow is now equal to 0
struct Vector2D {
var x = 0.0, y = 0.0
}
extension Vector2D {
static func + (left: Vector2D, right: Vector2D) -> Vector2D {
return Vector2D(x: left.x + right.x, y: left.y + right.y)
}
}
extension Vector2D {
static prefix func - (vector: Vector2D) -> Vector2D {
return Vector2D(x: -vector.x, y: -vector.y)
}
}