Swift知識(shí)點(diǎn)

? 和 ?。蛇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)有的額外功能:

  1. 繼承允許一個(gè)類(lèi)繼承另一個(gè)類(lèi)的特征;
  2. 類(lèi)型轉(zhuǎn)換允許你在運(yùn)行檢查和解釋一個(gè)類(lèi)實(shí)例的類(lèi)型;
  3. 反初始化器允許一個(gè)類(lèi)實(shí)例釋放任何其所被分配的資源;
  4. 引用計(jì)數(shù)允許不止一個(gè)對(duì)類(lèi)實(shí)例的引用。
  5. 結(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)
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容