? 和 ?。蛇x項(xiàng))
?代表變量可為nil(將變量變成了枚舉,要么為值,要么為nil),!代表強(qiáng)制展開(kāi),直接取值,不可能為nil
var optionalInteger: Int?
var optionalInteger: Optional<Int> //等價(jià)于上面那行代碼
if let constantName = someOptional { #可選綁定項(xiàng),如果賦值失敗就不進(jìn)入循環(huán)
statements
}
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! #requires an exclamation mark
let assumedString: String! = "An implicitly unwrapped optional string." #隱式展開(kāi)
let implicitString: String = assumedString #no need for an exclamation mark
a ?? b #等價(jià)于 a != nil ? a! : b
類(lèi)型安全
swift不支持隱式轉(zhuǎn)換,使用Int(val)進(jìn)行轉(zhuǎn)換
元組
元組中可以包含任何類(lèi)型的變量,常用于返回值。
let http404Error = (404, "Not Found")
let (code, message) = http404Error
print("\(code) " + message)
let(code, _) = http404Error #_表示不需要使用的變量
let (x, y) = (1, 2) #同時(shí)為兩個(gè)變量賦值
區(qū)間
for index in 1...5 { #閉區(qū)間,包括5
print("\(index) times 5 is \(index * 5)")
}
for index in 1..<5 { #開(kāi)區(qū)間,不包括5
print("\(index) times 5 is \(index * 5)")
}
for name in names[2...] { #單側(cè)區(qū)間 2 to end
print(name)
}
for name in names[...2] { #單側(cè)區(qū)間 start to 2
print(name)
}
String
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."
""" #用三個(gè)"標(biāo)記多行string
#String不能用Int下標(biāo)獲取Character
print(str[str.index(str.startIndex, offsetBy: 8)])
print(str[str.index(before: str.endIndex)])
print(str[str.index(after: str.startIndex)])
#刪除使用remove
let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex
welcome.removeSubrange(range) #范圍刪除
welcome.remove(at: welcome.index(before: welcome.endIndex)) #刪除單個(gè)
#插入使用insert
var welcome = "hello"
welcome.insert("!", at: welcome.endIndex) #插入單個(gè)
welcome.insert(contentsOf: " there", at: welcome.index(before: welcome.endIndex)) #插入字符串
#子字符串Substring,子字符串重用了原來(lái)字符串的內(nèi)存
let beginning = greeting[..<index] #beginning是Substring類(lèi)型
let newString = String(beginning) #轉(zhuǎn)換成String類(lèi)型,開(kāi)辟了新內(nèi)存
#前后綴
let scene = "Act 1, hello world"
scene.hasPrefix("Act 1")
scene.hasSuffix("world")
集合類(lèi)型
#數(shù)組
var someInts = Array<Int>() #創(chuàng)建空數(shù)組
var someInts = [Int]()
var shoppingList: [String] = ["Eggs", "Milk"] #字面量創(chuàng)建數(shù)組
var threeDoubles = Array(repeating: 0.0, count: 3) #使用默認(rèn)值創(chuàng)建數(shù)組
shoppingList[4...6] = ["Bananas", "Apples"] #將4-6的元素替換成新的集合
#插入刪除
shoppingList.insert("Maple Syrup", at: 0)
let mapleSyrup = shoppingList.remove(at: 0)
for (index, value) in shoppingList.enumerated() { #enumerated()同時(shí)返回index和值
print("Item \(index + 1): \(value)")
}
#Set
var letters = Set<Character>() #空集合
letters.sorted() #排序
oddDigits.union(evenDigits) #并
oddDigits.intersection(evenDigits) #交
oddDigits.subtracting(singleDigitPrimeNumbers) #減
oddDigits.symmetricDifference(singleDigitPrimeNumbers) #與非
#字典
var namesOfIntegers = [Int: String]() #空字典
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"] #字面量創(chuàng)建字典
let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") #更新字典,返回舊值(String?),如果key不存在則新建一條(此時(shí)返回nil)
airports["APL"] = nil #刪除一條
let removedValue = airports.removeValue(forKey: "DUB") #刪除一條,失敗返回nil
#遍歷
for (airportCode, airportName) in airports {
print("\(airportCode): \(airportName)")
}
for airportCode in airports.keys { #遍歷keys, airport.values遍歷value
print("Airport code: \(airportCode)")
}
let airportCodes = [String](airports.keys) #將keys輸出為數(shù)組
For循環(huán)
for name in names { #遍歷數(shù)組
print("Hello, \(name)!")
}
for (animalName, legCount) in numberOfLegs { #遍歷map
print("\(animalName)s have \(legCount) legs")
}
for index in 1...5 { #遍歷數(shù)字, 也可用1..<5,此時(shí)不包含5
print("\(index) times 5 is \(index * 5)")
}
let minuteInterval = 5 #以一定間隔循環(huán)
for tickMark in stride(from: 0, to: minutes, by: minuteInterval) { #不包含minutes
// render the tick mark every 5 minutes (0, 5, 10, 15 ... 45, 50, 55)
}
for tickMark in stride(from: 0, through: minutes, by: minuteInterval) { } #包含minutes
While循環(huán)
while condition { #先判斷再執(zhí)行
statements
}
repeat { #先執(zhí)行再判斷
statements
} while condition
Switch
let someCharacter: Character = "z"
switch someCharacter {
case "a":
print("The first letter of the alphabet") #自帶break,不會(huì)繼續(xù)執(zhí)行下一個(gè)case
case 1..<5: #區(qū)間匹配
...
case (_, 0): #元組匹配 或者case (1, 1)
...
case (-2...2, -2...2): #元組匹配加區(qū)間匹配
...
fallthrough #貫穿,此時(shí)繼續(xù)執(zhí)行下一個(gè)case
case "y", "z": #復(fù)合狀態(tài)
print("The last letter of the alphabet")
default:
print("Some other character")
}
#標(biāo)簽
gameLoop: while square != finalSquare { #命名while循環(huán)為gameLoop
diceRoll += 1
if diceRoll == 7 { diceRoll = 1 }
switch square + diceRoll {
case finalSquare:
break gameLoop #跳出while循環(huán)
case let newSquare where newSquare > finalSquare:
continue gameLoop
default:
square += diceRoll
square += board[square]
}
}
print("Game over!")
Guard
在滿足條件后代碼會(huì)繼續(xù)執(zhí)行,否則執(zhí)行else代碼塊
guard let name = person["name"] else {
return
}
函數(shù)
#使用元組作為返回值
func minMax(array: [Int]) -> (min: Int, max: Int) {
var currentMin = array[0]
var currentMax = array[0]
#...
return (currentMin, currentMax)
}
let bounds = minMax(array: [1,2,3])
#bounds.min == 1
#bounds.max == 3
func minMax(array: [Int]) -> (min: Int, max: Int)? { #可選元組
if array.isEmpty { return nil } //返回值可為空
#...
}
# 形參名和實(shí)參名
func greet(person: String, from hometown: String) -> String {
return "Hello \(person)! Glad you could visit from \(hometown)."
} # from是實(shí)參名,hometown是形參名
print(greet(person: "Bill", from: "Cupertino"))
func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
#...
} # _ 表示省略實(shí)參名,之后可直接傳入數(shù)據(jù)
someFunction(1, secondParameterName: 2)
# 可變形參
func arithmeticMean(_ numbers: Double...) -> Double { # 使用...表現(xiàn)可變形參
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
} # 此時(shí)numbers是[Double]數(shù)組
# 輸入輸出形參
func swapTwoInts(_ a: inout Int, _ b: inout Int) { # 使用inout關(guān)鍵字(類(lèi)似C++引用)
let temporaryA = a
a = b
b = temporaryA
} # 此時(shí)傳入?yún)?shù)會(huì)被實(shí)際改變
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt) # 傳入的時(shí)候要加&
# 函數(shù)類(lèi)型
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
} # addTwoInts的函數(shù)類(lèi)型是(Int, Int) -> Int
var mathFunction: (Int, Int) -> Int = addTwoInts # 可以像其他類(lèi)型一樣設(shè)置函數(shù)變量,也可以寫(xiě)成var mathFunction = addTwoInts
print("Result: \(mathFunction(2, 3))")
# 函數(shù)類(lèi)型作為形參
func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) { # 函數(shù)類(lèi)型變量作為形參
print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
# 函數(shù)類(lèi)型作為返回值
func stepForward(_ input: Int) -> Int {
return input + 1
}
func stepBackward(_ input: Int) -> Int {
return input - 1
}
func chooseStepFunction(backwards: Bool) -> (Int) -> Int { # 返回函數(shù)類(lèi)型
return backwards ? stepBackward : stepForward
}
var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
# 內(nèi)嵌函數(shù)
func chooseStepFunction(backward: Bool) -> (Int) -> Int { #內(nèi)嵌函數(shù)也能捕獲夫函數(shù)中的變量
func stepForward(input: Int) -> Int { return input + 1 } # 在函數(shù)內(nèi)部聲明函數(shù)
func stepBackward(input: Int) -> Int { return input - 1 }
return backward ? stepBackward : stepForward
}
閉包
閉包能捕獲上下文中的常量和變量
{ (parameters) -> (return type) in
statements
}
#第一種方法是寫(xiě)一個(gè)函數(shù),然后傳入sorted(by:)
func backward(_ s1: String, _ s2: String) -> Bool {
return s1 > s2
}
var reversedNames = names.sorted(by: backward)
#閉包版本
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
})
#簡(jiǎn)寫(xiě)版本
reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } ) #可以去掉形參類(lèi)型和返回類(lèi)型,根據(jù)上下文自動(dòng)判斷
reversedNames = names.sorted(by: { $0 > $1 } ) #使用$x表示第x個(gè)形參,可以直接寫(xiě)函數(shù)體
#逃逸閉包
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) { #需要加@escaping關(guān)鍵字
completionHandlers.append(completionHandler) #閉包被返回出函數(shù)
}
#自動(dòng)閉包
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: () -> String) {
print("Now serving \(customerProvider())!")
} #普通閉包
serve(customer: { customersInLine.remove(at: 0) } ) #調(diào)用時(shí)需要{ }
func serve(customer customerProvider: @autoclosure () -> String) {
print("Now serving \(customerProvider())!")
} #自動(dòng)閉包,使用@autoclosure關(guān)鍵字
serve(customer: customersInLine.remove(at: 0)) #調(diào)用時(shí)不需要{ }
枚舉
enum CompassPoint {
case north // 要寫(xiě)case,C++中不寫(xiě)
case south // 新行不用逗號(hào)隔開(kāi),C++需要
case east
case west
} // 最后不用; C++需要
var directionToHead = CompassPoint.west //聲明時(shí)需要枚舉名
directionToHead = .east // 之后再使用可以不寫(xiě)枚舉名
for compass in CompassPoint.allCases { //使用allCases來(lái)遍歷所有枚舉
print(compass)
}
//關(guān)聯(lián)值
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
var productBarcode = Barcode.upc(8, 85909, 51226, 3) //聲明upc形式
productBarcode = .qrCode("ABCDEFGHIJKLMNOP") //改為qrCode模式,upc被替換
switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check): //取出枚舉關(guān)聯(lián)的值
print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
case let .qrCode(productCode): //另一種寫(xiě)法,let在外
print("QR code: \(productCode).")
}
// 原始值
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune //原始值為Int,從1開(kāi)始
}
let positionToFind = 11
if let somePlanet = Planet(rawValue: positionToFind) { //rawValue返回Planet?
//...
}
// 遞歸枚舉
indirect enum ArithmeticExpression { //使用indirect關(guān)鍵字
case number(Int)
case addition(ArithmeticExpression, ArithmeticExpression)
case multiplication(ArithmeticExpression, ArithmeticExpression)
}
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
類(lèi)
類(lèi)有而結(jié)構(gòu)體沒(méi)有的額外功能:
- 繼承允許一個(gè)類(lèi)繼承另一個(gè)類(lèi)的特征;
- 類(lèi)型轉(zhuǎn)換允許你在運(yùn)行檢查和解釋一個(gè)類(lèi)實(shí)例的類(lèi)型;
- 反初始化器允許一個(gè)類(lèi)實(shí)例釋放任何其所被分配的資源;
- 引用計(jì)數(shù)允許不止一個(gè)對(duì)類(lèi)實(shí)例的引用。
- 結(jié)構(gòu)體是值類(lèi)型(拷貝傳值),類(lèi)是引用類(lèi)型(引用傳值)
=== 和!== 用于判斷兩個(gè)變量是否指向同一個(gè)實(shí)例(類(lèi)似于C++兩個(gè)指針指向同一個(gè)對(duì)象)
Swift 的 String , Array 和 Dictionary類(lèi)型是作為結(jié)構(gòu)體來(lái)實(shí)現(xiàn)的,使用拷貝傳值
屬性
//延遲屬性(懶加載)
class DataImporter {
var fileName = "data.txt"
// ...
}
class DataManager {
lazy var importer = DataImporter() //使用lazy關(guān)鍵字
var data = [String]()
//...
}
let manager = DataManager()
manager.data.append("Some data") //此時(shí)仍沒(méi)加載DataImporter
print(manager.importer.fileName) //只有在第一次使用importer的時(shí)候才會(huì)加載
//計(jì)算屬性
struct Rect {
var origin = Point()
var size = Size()
var center: Point { //center不是真正存儲(chǔ)下來(lái)的Point結(jié)構(gòu),而是計(jì)算出來(lái)的
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set(newCenter) {
origin.x = newCenter.x - (size.width / 2)
origin.y = newCenter.y - (size.height / 2)
}
}
var volume: Double { //只讀屬性,只有g(shù)et函數(shù)(簡(jiǎn)寫(xiě))
return size * depth
}
}
//屬性觀察者
class StepCounter {
var totalSteps: Int = 0 { //全局變量也可以設(shè)置觀察者
willSet(newTotalSteps) { //willSet是在賦值之前觸發(fā)
print("About to set totalSteps to \(newTotalSteps)")
}
didSet { //didSet在賦值之后觸發(fā)
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
stepCounter.totalSteps = 360
//類(lèi)型屬性(靜態(tài)成員)
struct SomeStructure {
static var storedTypeProperty = "Some value." //使用static關(guān)鍵字
static var computedTypeProperty: Int {
return 1
}
}
print(SomeStructure.storedTypeProperty) //使用的時(shí)候 類(lèi)名.屬性名
//類(lèi)方法
class SomeClass {
class func someTypeMethod() { //使用class關(guān)鍵字
// type method implementation goes here
}
}
SomeClass.someTypeMethod() //使用的時(shí)候 類(lèi)名.方法名
//內(nèi)嵌類(lèi)型
struct BlackjackCard {
// nested Suit enumeration
enum Suit: Character {
case Spades = "?", Hearts = "?", Diamonds = "?", Clubs = "?"
}
}
下標(biāo)
subscript(index: Int) -> Int { //使用關(guān)鍵字subscript ,輸入類(lèi)型Int, 返回類(lèi)型不定
get {
// return an appropriate subscript value here
}
set(newValue) {
// perform a suitable setting action here
}
}
繼承
class Train: Vehicle {
override func makeNoise() { //重寫(xiě)方法
print("Choo Choo")
}
}
final class Car: Vehicle { // final關(guān)鍵字表示此類(lèi)不能被繼承
var gear = 1
override var description: String { //重寫(xiě)get函數(shù)
return super.description + " in gear \(gear)"
}
final func makeNoise() { //final關(guān)鍵字
print("Tu Tu")
}
}
初始化(構(gòu)造函數(shù))
struct Celsius {
var temperatureInCelsius: Double
let text: String
init(fromFahrenheit fahrenheit: Double) {
temperatureInCelsius = (fahrenheit - 32.0) / 1.8
text = "Fahrenheit" //常量可在init()函數(shù)中賦值,之后不可改變
}
init(fromKelvin kelvin: Double) {
temperatureInCelsius = kelvin - 273.15
text = "Kelvin"
}
init(_ celsius: Double) { //隱藏參數(shù)名形式
temperatureInCelsius = celsius
}
}
let bodyTemperature = Celsius(37.0) //直接傳參數(shù)
//結(jié)構(gòu)體的成員初始化器
struct Size {
var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0) //編譯器自動(dòng)生成init(width: height:)初始化方法
//初始化器委托
struct Rect {
var origin = Point()
var size = Size()
init() {}
init(origin: Point, size: Size) {
self.origin = origin
self.size = size
}
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) //使用init(origin: ,size:)初始化,類(lèi)似于C++
}
}
//指定初始化器和便捷初始化器
class Food {
var name: String
init(name: String) { //指定初始化器
self.name = name
}
convenience init() { //便捷初始化器
self.init(name: "[Unnamed]") //便捷初始化器調(diào)用指定初始化器,前面加convenience關(guān)鍵字
}
}
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) { //指定初始化器
self.quantity = quantity //先初始化自己的屬性,再調(diào)用父類(lèi)初始化器
super.init(name: name) //調(diào)用父類(lèi)指定初始化器
self.name += "_1" //調(diào)用父類(lèi)初始化器后才可以重新給基礎(chǔ)屬性賦值
}
override convenience init(name: String) { //便攜初始化器
self.init(name: name, quantity: 1)
quantity -= 1 //便攜初始化器要先調(diào)用其他初始化器,然后再對(duì)屬性重新賦值
}
}
class ShoppingListItem: RecipeIngredient { //沒(méi)有重寫(xiě)初始化器,自動(dòng)繼承父類(lèi)的所有初始化器
var purchased = false
var description: String {
var output = "\(quantity) x \(name)"
output += purchased ? " ?" : " ?"
return output
}
}
//可失敗初始化器
struct Animal {
let species: String
init?(species: String) { //init?表示可失敗初始化器,其可被子類(lèi)的不可失敗初始化器override
if species.isEmpty { return nil } //return nil表示初始化失敗
self.species = species
}
}
//必要初始化器
class SomeClass {
required init() { //使用required關(guān)鍵字
// initializer implementation goes here
}
}
class SomeSubclass: SomeClass {
required init() { //其子類(lèi)必須override這個(gè)初始化器, 前面不需要override關(guān)鍵字
// subclass implementation of the required initializer goes here
}
}
//使用閉包給屬性賦默認(rèn)值
struct Chessboard {
let boardColors: [Bool] = {
var temporaryBoard = [Bool]()
var isBlack = false
for i in 1...8 {
for j in 1...8 {
temporaryBoard.append(isBlack)
isBlack = !isBlack
}
isBlack = !isBlack
}
return temporaryBoard
}() //{ }后跟()表示立即執(zhí)行此閉包
func squareIsBlackAt(row: Int, column: Int) -> Bool {
return boardColors[(row * 8) + column]
}
}
反初始化器(析構(gòu)函數(shù))
使用deinit關(guān)鍵字,因?yàn)閟wift使用ARC,所以一般不需要自己手動(dòng)釋放內(nèi)存,只有在有特殊任務(wù)要在銷(xiāo)毀對(duì)象時(shí)處理的時(shí)候才會(huì)實(shí)現(xiàn)反初始化器
ARC 自動(dòng)引用計(jì)數(shù)
可能遇到循環(huán)強(qiáng)引用的問(wèn)題,此時(shí)需要弱引用或無(wú)主引用解除循環(huán)。(對(duì)于生命周期中會(huì)變?yōu)?nil 的實(shí)例使用弱引用。對(duì)于初始化賦值后再也不會(huì)被賦值為 nil 的實(shí)例,使用無(wú)主引用。)
# 弱引用
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { print("\(name) is being deinitialized") }
}
class Apartment {
let unit: String
init(unit: String) { self.unit = unit }
weak var tenant: Person? #弱應(yīng)用使用weak關(guān)鍵字,tenant可為nil
deinit { print("Apartment \(unit) is being deinitialized") }
}
# 無(wú)主引用
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit { print("\(name) is being deinitialized") }
}
class CreditCard {
let number: UInt64
unowned let customer: Customer # 無(wú)主引用使用unowned關(guān)鍵字,customer不可為nil
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
deinit { print("Card #\(number) is being deinitialized") }
}
#閉包和self循環(huán)強(qiáng)引用
lazy var someClosure: () -> String = {
[unowned self, weak delegate = self.delegate!] in #將self設(shè)置為unowned,
// closure body goes here
}
lazy var asHTML: () -> String = {
[unowned self] in # 加上這句話保證沒(méi)有循環(huán)強(qiáng)引用
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
可選鏈
如果通過(guò)可選鏈取回一個(gè) Int 值,就一定會(huì)返回 Int? ,不論通過(guò)了多少層的可選鏈;
如果通過(guò)可選鏈訪問(wèn) Int? 值, Int? 一定就是返回的類(lèi)型,無(wú)論通過(guò)了多少層的可選鏈。
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
func printNumberOfRooms() {
print("The number of rooms is \(numberOfRooms)")
}
}
if let roomCount = john.residence?.numberOfRooms { #如果residence為nil,返回nil
print("John's residence has \(roomCount) room(s).")
} else {
print("Unable to retrieve the number of rooms.")
}
if john.residence?.printNumberOfRooms() != nil { #函數(shù)也可以放入可選鏈中判定是否為nil
print("It was possible to print the number of rooms.")
} else {
print("It was not possible to print the number of rooms.")
}
錯(cuò)誤處理
func canThrowErrors() throws -> String //拋出函數(shù),在形參后面加throws關(guān)鍵字
enum VendingMachineError: Error { //繼承Error類(lèi)來(lái)定義Error類(lèi)型
case invalidSelection
case insufficientFunds(coinsNeeded: Int)
case outOfStock
}
func vend(itemNamed name: String) throws {
guard let item = inventory[name] else { //guard進(jìn)行條件判斷
throw VendingMachineError.invalidSelection
}
}
func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
let snackName = favoriteSnacks[person] ?? "Candy Bar"
try vendingMachine.vend(itemNamed: snackName) //使用try來(lái)獲取錯(cuò)誤
}
var vendingMachine = VendingMachine()
vendingMachine.coinsDeposited = 8
do { //使用do-catch獲取錯(cuò)誤
try buyFavoriteSnack("Alice", vendingMachine: vendingMachine) //如果通過(guò),執(zhí)行下面的代碼
// Enjoy delicious snack
} catch VendingMachineError.invalidSelection { //如果返回錯(cuò)誤,根據(jù)錯(cuò)誤類(lèi)型執(zhí)行相應(yīng)代碼
print("Invalid Selection.")
} catch VendingMachineError.outOfStock {
print("Out of Stock.")
} catch VendingMachineError.insufficientFunds(let coinsNeeded) {
print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
}
let x = try? someThrowingFunction() //如果try失敗,返回nil
// 延遲執(zhí)行
func processFile(filename: String) throws {
if exists(filename) {
let file = open(filename)
defer { // 使用defer關(guān)鍵字
close(file) //此段代碼會(huì)在作用域最后執(zhí)行
}
while let line = try file.readline() {
// Work with the file.
}
// close(file) is called here, at the end of the scope.
}
}
類(lèi)型轉(zhuǎn)換
var movieCount = 0
var songCount = 0
for item in library {
if item is Movie { //使用is判斷實(shí)例是否是某類(lèi)型
movieCount += 1
} else if item is Song {
songCount += 1
}
}
//向下類(lèi)型轉(zhuǎn)換
for item in library {
if let movie = item as? Movie { //可選項(xiàng)轉(zhuǎn)換, as?, 如果失敗返回nil
print("Movie: '\(movie.name)', dir. \(movie.director)")
} else if let song = item as! Song { //強(qiáng)制項(xiàng)轉(zhuǎn)換, as!, 如果失敗編譯報(bào)錯(cuò)
print("Song: '\(song.name)', by \(song.artist)")
}
}
//Any, AnyObject
var things = [Any]() //Any代表任何類(lèi)型,AnyObject表示任何類(lèi)型的實(shí)例
things.append(0)
things.append(0.0)
things.append(42)
things.append(3.14159)
things.append("hello")
things.append((3.0, 5.0))
things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
things.append({ (name: String) -> String in "Hello, \(name)" })
擴(kuò)展
extension Double { // extension加類(lèi)名
var km: Double { return self * 1_000.0 }
var m: Double { return self }
}
協(xié)議
protocol FullyNamed { // 使用protocol關(guān)鍵字
var fullName: String { get } //要求類(lèi)必須有一個(gè)fullName變量
func random() -> Double //要求實(shí)現(xiàn)函數(shù)
}
struct Person: FullyNamed { // 使用: ProtocolName來(lái)給類(lèi)添加協(xié)議
var fullName: String
//...
func random() -> Double { //實(shí)現(xiàn)協(xié)議函數(shù)
lastRandom = ((lastRandom * a + c).truncatingRemainder(dividingBy:m))
return lastRandom / m
}
}
class Dice {
let sides: Int
let generator: FullyNamed //將協(xié)議作為類(lèi)型,此變量可以等于任何實(shí)現(xiàn)了該協(xié)議的實(shí)例
}
//在擴(kuò)展中添加協(xié)議
protocol TextRepresentable {
var textualDescription: String { get }
}
extension Dice: TextRepresentable { //將協(xié)議實(shí)現(xiàn)在擴(kuò)展中,即使沒(méi)有原始類(lèi)的源代碼也能使其遵守協(xié)議
var textualDescription: String {
return "A \(sides)-sided dice"
}
}
protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol { //類(lèi)專(zhuān)用的協(xié)議,前面加AnyObject
// class-only protocol definition goes here
}
泛型(C++模板)
func swapTwoValues<T>(_ a: inout T, _ b: inout T) { //函數(shù)名后加<T> , T作為類(lèi)型
let temporaryA = a
a = b
b = temporaryA
}
swapTwoValues(&someInt, &anotherInt) // 使用時(shí)會(huì)自動(dòng)推斷類(lèi)型
struct Stack<Element> { //泛型結(jié)構(gòu)體
var items = [Element]()
mutating func push(_ item: Element) { //mutating表示異變(只在結(jié)構(gòu)體中使用),此函數(shù)可改變結(jié)構(gòu)體屬性值,
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
}
var stackOfStrings = Stack<String>() //使用的時(shí)候注明類(lèi)型
stackOfStrings.push("uno")
extension Stack { //擴(kuò)展泛型結(jié)構(gòu)不需要加類(lèi)型
var topItem: Element? {
return items.isEmpty ? nil : items[items.count - 1]
}
}
//泛型限定
func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? { //T: Equatable 限定T必須遵守Equatable協(xié)議
for (index, value) in array.enumerated() {
if value == valueToFind {
return index
}
}
return nil
}
訪問(wèn)控制
public class SomePublicClass {} //最開(kāi)放訪問(wèn)級(jí)別,所有模塊都可訪問(wèn)
internal class SomeInternalClass {} //默認(rèn)訪問(wèn)級(jí)別,同模塊內(nèi)可訪問(wèn)
fileprivate class SomeFilePrivateClass {} //文件內(nèi)可訪問(wèn)
private class SomePrivateClass {} //類(lèi)內(nèi)可訪問(wèn)
位運(yùn)算符
左右移動(dòng)
無(wú)符號(hào)數(shù)直接移動(dòng),越界拋棄,末尾補(bǔ)0
有符號(hào)數(shù)中,負(fù)數(shù)存儲(chǔ)的是 2 的 n 次方減去它的絕對(duì)值,n 為數(shù)值位的位數(shù)。一個(gè) 8 位的數(shù)有七個(gè)數(shù)值位,所以是 2 的 7 次方(128) 。此編碼稱(chēng)為二進(jìn)制補(bǔ)碼,這種存儲(chǔ)方式可使有符號(hào)數(shù)的左右移動(dòng)行為和無(wú)符號(hào)數(shù)一致。(向右移動(dòng)時(shí),對(duì)產(chǎn)生的空位使用符號(hào)位填補(bǔ))
let decimalInteger = 17
let binaryInteger = 0b10001 // 二進(jìn)制的17, 0b
let octalInteger = 0o21 // 八進(jìn)制的17, 0o
let hexadecimalInteger = 0x11 // 十六進(jìn)制, 0x
let initialBits: UInt8 = 0b00001111
let invertedBits = ~initialBits // equals 11110000 // 取反
let firstBits: UInt8 = 0b00010100
let otherBits: UInt8 = 0b00000101
let outputBits = firstBits ^ otherBits // equals 00010001 // 異或,兩位不相等時(shí)取1
操作符重載
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)
}
static prefix func - (vector: Vector2D) -> Vector2D { // prefix關(guān)鍵字表示這是一個(gè)前置運(yùn)算符
return Vector2D(x: -vector.x, y: -vector.y)
}
static func += (left: inout Vector2D, right: Vector2D) { // 重載組合運(yùn)算符,第一個(gè)算符要設(shè)為inout,然后沒(méi)有返回值
left = left + right
}
}
extension Vector2D: Equatable { // 重載==要實(shí)現(xiàn)Equatable協(xié)議
static func == (left: Vector2D, right: Vector2D) -> Bool {
return (left.x == right.x) && (left.y == right.y)
}
}