1. 基础
常量 && 变量
// 常量
let age = 20
// 变量
var weight = 120.4
// 类型标识
var welcomeMessage: String
welcomeMessage = "Hello"
// 统一类型
var red, green, blue: Double
整数
Int:在32位平台上是Int32,在64位平台上是Int64
UInt:在32位平台上是UInt32,在64位平台上是UInt64
其他整数:Int8,Int16,Int32,Int64
整数范围
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
浮点数
Float:32位浮点数
Double:64位浮点数
类型安全和类型推导
Swift 是类型安全语言,在编译期间执行类型检查来避免类型错误,但这并不意味着定义变量都要指定类型,Swift 提供类型推导机制,比如:
// Int 类型
var age = 20
// Double 类型
var weight = 120.5
// Double 类型
var height = 170 + 1.5
不同类型之间的数字运算需要做显式转换,隐式转换不被允许的:
let three = 3
let pointOneFourOneFiveNine = 0.14159
// 不加Double() 转换,报错
let pi = Double(three) + pointOneFourOneFiveNine
类型别名
typealias AudioSample = UInt16
var maxAmplitudeFound = AudioSample.min
布尔类型
let turnOn = true
if turnOn {
print("turnOn is true")
} else {
print("turnOn is false")
}
由于类型安全,Swift 中非布尔类型不能代替布尔类型使用,比如代码报错:
// 编译报错
if 1 {
print("1 不能代替 true")
}
元组
元组是一组数据的集合,可以是不同的数据类型
// 定义一个元组,类型:(Int, String)
let http404Error = (404, "Not Found")
// 获取数据
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
print("The status message is \(statusMessage)")
// 获取部分数据
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)")
print("The status message is \(http200Status.description)")
Optional(可选变量)
optional 修饰的变量代表该变量可能有值,也可能没值。没值通过 nil 来表示
不能将非可选变量的值设置为nil
var serverResponseCode: Int? = 404
serverResponseCode = nil
// 无初始化值默认为 nil
var surveyAnswer: String?
Swift 中的 nil 和 OC 中的 nil 不一样,OC 中的 nil 代表是 空对象指针,用在对象类型上,Swift 的 nil 表示某个变量没有值,所有类型都可以使用。
可选值的解包
强制解包
当确认某个变量一定有值的时候,可以使用强制解包符号 !
var convertedNumber: Int? = 404
if convertedNumber != nil {
print("convertedNumber has an integer value of \(convertedNumber!).")
}
可选绑定
if,while 条件语句可以使用可选绑定来解包
var convertedNumber: Int? = 404
if let actualNumber = convertedNumber {
print("The convertedNumber has an integer value of \(actualNumber)")
} else {
print("The convertedNumber has no value")
}
// 多个解包操作,有一个返回 nil 则 if 语句条件判断失败
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
隐式解包
什么玩意?
let possibleString: String? = "An optional string."
// 需要解包使用
let forcedString: String = possibleString!
let assumedString: String! = "An implicitly unwrapped optional string."
// 不需要解包,根据类型推导,这里会自动强制解包
let implicitString: String = assumedString
// 不自动解包,optionalString 是 optional 类型
let optionalString = assumedString
错误处理
func makeASandwich() throws {
// this function may or may not throw an error
}
do {
try makeASandwich()
eatASandwich()
} catch SandwichError.outOfCleanDishes {
washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
buyGroceries(ingredients)
}
Assertions and Preconditions
断言,他们之间的区别是 Assertions 只在 Debug 环境下生效,Preconditions 在 Debug 和 Product 环境下都生效。
let age = -3
assert(age >= 0, "A person's age can't be less than zero.")
precondition(index > 0, "Index must be greater than zero.")
基本运算符
赋值运算符(=)没有返回值
默认算术运算符不允许值溢出
运算符特殊操作:
// 字符串连接
"hello, " + "world" // equals "hello, world"
// 溢出操作符
let c = a &+ b
// 取余运算
a % b
a = (b x some multiplier) + remainder
-9 % 4 // equals -1
-9 = (4 x -2) + -1
// 三元
a != nil ? a! : b 等价于 a ?? b
// 区间运算符
// 闭区间 a...b
for index in 1...5 {
print("\(index)")
//打印 1 2 3 4 5
}
// 半开区间 a..
2. 字符和字符串
初始化操作
var emptyString = "" // empty string literal
var anotherEmptyString = String() // initializer syntax
if emptyString.isEmpty {
print("Nothing to see here")
}
// 可变字符串
var variableString = "Horse"
variableString += " and carriage" // Horse and carriage
// 不可变字符串
let constantString = "Highlander"
constantString += " and another Highlander" // 编译报错
字符串字面量
// 单行
let someString = "Some string literal value"
// 多行
let quotation = """
The White Rabbit put on his spectacles. "Where shall I begin,
please your Majesty?" he asked.
"Begin at the beginning," the King said gravely, "and go on
till you come to the end; then stop."
"""
扩展字符
// \n 不会换行
let str = #"Line 1\nLine 2"#
// \n 会换行
let str = #"Line 1\#nLine 2"#
字符操作
for character in "Dog!" {
print(character)
}
// D o g !
let exclamationMark: Character = "!"
let catCharacters: [Character] = ["C", "a", "t", "!", ""]
字符串操作
let string1 = "hello"
let string2 = " there"
var welcome = string1 + string2
// welcome now equals "hello there"
var instruction = "look over"
instruction += string2
// instruction now equals "look over there"
// 字符串插入
let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
print(#"6 times 7 is \#(6 * 7)."#)
// Prints "6 times 7 is 42."
字符计数
// 特殊例子
var word = "cafe"
print("the number of characters in \(word) is \(word.count)")
// Prints "the number of characters in cafe is 4"
word += "\u{301}" // COMBINING ACUTE ACCENT, U+0301
print("the number of characters in \(word) is \(word.count)")
// Prints "the number of characters in café is 4"
字符访问
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
for index in greeting.indices {
print("\(greeting[index]) ", terminator: "")
}
// Prints "G u t e n T a g ! "
插入 && 删除
var welcome = "hello"
welcome.insert("!", at: welcome.endIndex)
// welcome now equals "hello!"
welcome.insert(contentsOf: " there", at: welcome.index(before: welcome.endIndex))
// welcome now equals "hello there!"
welcome.remove(at: welcome.index(before: welcome.endIndex))
// welcome now equals "hello there"
let range = welcome.index(welcome.endIndex, offsetBy: -6)..
3. 集合类型
Swift 提供三种集合类型,Arrays,Sets,Dictionarys。
用 var 定义的集合就是可变集合
Arrays
Arrays 存储相同数据类型,元素有序,可重复
let a:[Any] = [1,2,"33"] 这个类型不一致是什么鬼?
var someInts = [Int]()
someInts.append(3)
someInts = []
var threeDoubles = Array(repeating: 0.0, count: 3)
// threeDoubles is of type [Double], and equals [0.0, 0.0, 0.0]
var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
// anotherThreeDoubles is of type [Double], and equals [2.5, 2.5, 2.5]
var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles is inferred as [Double], and equals [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]
var shoppingList: [String] = ["Eggs", "Milk"]
// 类型推导
var shoppingList = ["Eggs", "Milk"]
if shoppingList.isEmpty {
print("The shopping list is empty.")
} else {
print("The shopping list is not empty.")
}
// 用 "Bananas", "Apples" 替换 [4-6]位置的元素
shoppingList[4...6] = ["Bananas", "Apples"]
shoppingList.insert("Maple Syrup", at: 0)
let mapleSyrup = shoppingList.remove(at: 0)
// 遍历
for item in shoppingList {
print(item)
}
for (index, value) in shoppingList.enumerated() {
print("Item \(index + 1): \(value)")
}
Sets
Sets 存储相同数据类型,元素无序,不可重复,Sets 中的元素必须可以计算哈希值,本质上 Sets 是通过哈希表实现的。
Sets 定义类型关键字不能省略,因为表示语法和数组类似的
var letters = Set()
letters.insert("a")
// letters now contains 1 value of type Character
letters = []
// letters is now an empty set, but is still of type Set
var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
// 插入
favoriteGenres.insert("Jazz")
// 删除
if let removedGenre = favoriteGenres.remove("Rock") {
print("\(removedGenre)? I'm over it.")
} else {
print("I never much cared for that.")
}
// Prints "Rock? I'm over it."
// 遍历
for genre in favoriteGenres {
print("\(genre)")
}
// 集合操作(交集,并集等)
let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]
oddDigits.union(evenDigits).sorted()
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
oddDigits.intersection(evenDigits).sorted()
// []
oddDigits.subtracting(singleDigitPrimeNumbers).sorted()
// [1, 9]
oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted()
// [1, 2, 9]
Dictionaries
Dictionaries 存储 key-value 对
var namesOfIntegers = [Int: String]()
namesOfIntegers[16] = "sixteen"
// namesOfIntegers now contains 1 key-value pair
namesOfIntegers = [:]
// namesOfIntegers is once again an empty dictionary of type [Int: String]
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
var airports = ["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 airportName = airports["DUB"] {
print("The name of the airport is \(airportName).")
} else {
print("That airport is not in the airports dictionary.")
}
if let removedValue = airports.removeValue(forKey: "DUB") {
print("The removed airport's name is \(removedValue).")
} else {
print("The airports dictionary does not contain a value for DUB.")
}
// Prints "The removed airport's name is Dublin Airport."
for (airportCode, airportName) in airports {
print("\(airportCode): \(airportName)")
}
for airportCode in airports.keys {
print("Airport code: \(airportCode)")
}
// Airport code: LHR
// Airport code: YYZ
for airportName in airports.values {
print("Airport name: \(airportName)")
}
// Airport name: London Heathrow
// Airport name: Toronto Pearson
let airportCodes = [String](airports.keys)
// airportCodes is ["LHR", "YYZ"]
let airportNames = [String](airports.values)
// airportNames is ["London Heathrow", "Toronto Pearson"]
4. 控制流
For-In
for-in 可以用在序列上,比如 Arrays,Dictionarys,Sequence,Range等
let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names {
print("Hello, \(name)!")
}
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
print("\(animalName)s have \(legCount) legs")
}
for index in 1...5 {
print("\(index) times 5 is \(index * 5)")
// 5 10 15 20 25
}
var power = 10;
for _ in 1...5 { // 忽略 index 值
power *= 2;
}
// 半开区间
let minutes = 60
for tickMark in 0..
While
var num = 10
while num > 0 {
print("循环10次")
num --;
}
repeat {
print("循环10次")
num --;
} while num > 0
条件语句
let temperatureInFahrenheit = 90
if temperatureInFahrenheit <= 32 {
print("It's very cold. Consider wearing a scarf.")
} else if temperatureInFahrenheit >= 86 {
print("It's really warm. Don't forget to wear sunscreen.")
} else {
print("It's not that cold. Wear a t-shirt.")
}
Switch
在 Swift 中,switch 语法的 case 语句不会默认接着执行下一个case,不需要 break 来中断,在 switch 中使用 break 会导致退出整个 switch 的执行。要实现 C 语言中那种 case-by-case 的效果,需要使用 fallthrough 关键字。
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a", "A":
print("The letter A")
fallthrough
default:
print("Not the letter A")
}
范围匹配
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"
default:
naturalCount = "many"
}
print("There are \(naturalCount) \(countedThings).")
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")
}
// Prints "(1, 1) is inside the box"
Value Bindings
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))")
}
// Prints "on the x-axis with an x value of 2"
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")
}
// Prints "(1, -1) is on the line x == -y"
控制转移
continue,break,fallthrough 略
Labeled Statements
gameLoop: while square != finalSquare {
diceRoll += 1
if diceRoll == 7 { diceRoll = 1 }
switch square + diceRoll {
case finalSquare:
break gameLoop
case let newSquare where newSquare > finalSquare:
continue gameLoop
default:
square += diceRoll
square += board[square]
}
}
print("Game over!")
guard
和 if 类似,必须提供 else 分支,暂时不明用这玩意的必要性。
func greet(person: [String: String]) {
guard let name = person["name"] else {
return
}
print("Hello \(name)!")
guard let location = person["location"] else {
print("I hope the weather is nice near you.")
return
}
print("I hope the weather is nice in \(location).")
}
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
}
5.Functions
无返回值,无参数函数
func sayHelloWorld() {
print("hello, world")
}
单条语句隐式返回
func greeting(person: String) -> String {
"Hello, " + person + "!"
}
带参数,返回值,-> 是返回箭头
func greet(_ person:String, from user: String, world: String = "Hello") -> String {
return "to:\(person), greeting from:\(user), world:\(world)"
}
greet("Json", from:"End", world: "你好");
greet("Json", from:"End");
// 返回多个值
func minMax(array: [Int]) -> (min: Int, max: Int)? {
var currentMin = array[0]
var currentMax = array[0]
for value in array[1.. currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
可变参数
func arithmeticMean(_ numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
// returns 3.0, which is the arithmetic mean of these five numbers
arithmeticMean(3, 8.25, 18.75)
// returns 10.0, which is the arithmetic mean of these three numbers
inout 参数
默认情况,函数中的参数都是只读,不能修改,要修改需要使用 inout 修饰
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// Prints "someInt is now 107, and anotherInt is now 3"
函数类型
var mathFunction: (Int, Int) -> Int = addTwoInts
6. 闭包
语法
{ (parameters) -> return type in
statements
}
几个排序用法
// 数组排序
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
})
// 根据上下文类型推导
// 因为是 String 类型的数组调用 sort 方法
reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )
// 单表达式隐式返回
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
// 参数速记,可省略参数列表和 in 语句
reversedNames = names.sorted(by: { $0 > $1 } )
// 运算符函数,String 类型有定义 > 运算符函数
reversedNames = names.sorted(by: >)
尾随闭包
当闭包作为函数最后一个参数时,可以写成尾随闭包
func someFunctionThatTakesAClosure(closure: () -> Void) {
// 函数体代码
}
// 正常方式调用
someFunctionThatTakesAClosure(closure: {
// 闭包实现代码
})
// 尾随闭包调用
someFunctionThatTakesAClosure() {
// 闭包实现代码
}
// 上面的排序可以修改成尾随闭包调用
reversedNames = names.sorted() { $0 > $1 }
// 如果尾随闭包是函数的唯一参数,() 也可以省略
reversedNames = names.sorted { $0 > $1 }
变量捕捉
runningTotal 之所以会变是因为函数和闭包是引用类型
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
let incrementByTen = makeIncrementer(forIncrement: 10)
incrementByTen()
// returns a value of 10
incrementByTen()
// returns a value of 20
incrementByTen()
// returns a value of 30
逃避闭包
简单说就是一个闭包作为参数传入函数后,并不是在函数体内执行,而是在函数返回后才会在某个时机执行,比如异步请求,这时需要把这个闭包声明为逃逸闭包,之所以要明确是不是逃逸闭包,应该是为了内存优化管理
var completionHandlers = [() -> Void]()
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
Autoclosures
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count)
// Prints "5"
let customerProvider = { customersInLine.remove(at: 0) }
print(customersInLine.count)
// Prints "5"
print("Now serving \(customerProvider())!")
// Prints "Now serving Chris!"
print(customersInLine.count)
// Prints "4"