您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“什么是Swift語(yǔ)法”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“什么是Swift語(yǔ)法”吧!
Swift 是一門開發(fā) iOS, macOS, watchOS 和 tvOS 應(yīng)用的新語(yǔ)言。
swift 是一種安全,快速和互動(dòng)的編程語(yǔ)言。
swift 支持代碼預(yù)覽(playgrounds),這個(gè)特性可以允許程序員在不編譯和運(yùn)行應(yīng)用程序的前提下運(yùn)行 Swift 代碼并實(shí)時(shí)查看結(jié)果。
Swift 通過(guò)采用現(xiàn)代編程模式來(lái)避免大量常見(jiàn)編程錯(cuò)誤:
變量始終在使用前初始化。
檢查數(shù)組索引超出范圍的錯(cuò)誤。
檢查整數(shù)是否溢出。
可選值確保明確處理 nil 值。
內(nèi)存被自動(dòng)管理。
錯(cuò)誤處理允許從意外故障控制恢復(fù)。
聲明常量和變量, 常量和變量必須在使用前聲明,使用 let 來(lái)聲明常量,使用 var 來(lái)聲明變量。
示例:
let maximumNumberOfLoginAttempts = 10 var currentLoginAttempt = 0 // 類型注解 var welcomeMessage: String
單行注釋雙正斜杠(//), 多行注釋(/* 多行的 */)。Swift 的多行注釋可以嵌套在其它的多行注釋之中。
示例:
// 這是一個(gè)注釋 /* 這也是一個(gè)注釋, 但是是多行的 */ /* 這是第一個(gè)多行注釋的開頭 /* 這是第二個(gè)被嵌套的多行注釋 */ 這是第一個(gè)多行注釋的結(jié)尾 */
Swift 并不強(qiáng)制要求你在每條語(yǔ)句的結(jié)尾處使用分號(hào)(;)。
同一行內(nèi)寫多條獨(dú)立的語(yǔ)句必須用分號(hào)分隔。
let cat = "????"; print(cat) // 輸出“????”
統(tǒng)一使用 Int 可以提高代碼的可復(fù)用性,避免不同類型數(shù)字之間的轉(zhuǎn)換, 并且匹配數(shù)字的類型推斷。
示例:
let minValue = UInt8.min // minValue 為 0,是 UInt8 類型let maxValue = UInt8.max // maxValue 為 255,是 UInt8 類型
Swift 是一門類型安全的語(yǔ)言,這意味著 Swift 可以讓你清楚地知道值的類型。
如果你沒(méi)有顯式指定類型,Swift 會(huì)使用類型推斷來(lái)選擇合適的類型。(int、double)。
示例:
let meaningOfLife = 42 // meaningOfLife 會(huì)被推測(cè)為 Int 類型let pi = 3.14159 // pi 會(huì)被推測(cè)為 Double 類型
示例:
let decimalInteger = 17let binaryInteger = 0b10001 // 二進(jìn)制的17let octalInteger = 0o21 // 八進(jìn)制的17let hexadecimalInteger = 0x11 // 十六進(jìn)制的17
類型別名(type aliases)就是給現(xiàn)有類型定義另一個(gè)名字。你可以使用 typealias 關(guān)鍵字來(lái)定義類型別名。
示例:
typealias AudioSample = UInt16 var maxAmplitudeFound = AudioSample.min // maxAmplitudeFound 現(xiàn)在是 0
示例:
let orangesAreOrange = truelet turnipsAreDelicious = false
元組(tuples)把多個(gè)值組合成一個(gè)復(fù)合值。元組內(nèi)的值可以是任意類型,并不要求是相同類型。
示例:
let http404Error = (404, "Not Found") // http404Error 的類型是 (Int, String),值是 (404, "Not Found")
使用可選類型(optionals)來(lái)處理值可能缺失的情況??蛇x類型表示兩種可能:或者有值, 你可以解析可選類型訪問(wèn)這個(gè)值, 或者根本沒(méi)有值。
示例:
var serverResponseCode: Int? = 404 // serverResponseCode 包含一個(gè)可選的 Int 值 404 serverResponseCode = nil // serverResponseCode 現(xiàn)在不包含值
錯(cuò)誤處理,應(yīng)對(duì)程序執(zhí)行中可能會(huì)遇到的錯(cuò)誤條件。
示例:
func makeASandwich() throws { // ... }do { try makeASandwich() eatASandwich() } catch SandwichError.outOfCleanDishes { washDishes() } catch SandwichError.missingIngredients(let ingredients) { buyGroceries(ingredients) }
斷言和先決條件,是在運(yùn)行時(shí)所做的檢查。
let age = -3 assert(age >= 0, "A person's age cannot be less than zero") // 因?yàn)?nbsp;age < 0,所以斷言會(huì)觸發(fā)
Swift 支持大部分標(biāo)準(zhǔn) C 語(yǔ)言的運(yùn)算符,還提供了 C 語(yǔ)言沒(méi)有的區(qū)間運(yùn)算符,例如 a..<b 或 a...b。
運(yùn)算符分為一元、二元和三元運(yùn)算符。
閉區(qū)間運(yùn)算符(a...b)定義一個(gè)包含從 a 到 b(包括 a 和 b)的所有值的區(qū)間。
半開區(qū)間運(yùn)算符(a..<b)定義一個(gè)從 a 到 b 但不包括 b 的區(qū)間。
閉區(qū)間操作符有另一個(gè)表達(dá)形式,可以表達(dá)往一側(cè)無(wú)限延伸的區(qū)間,(a...,...b)。
示例:
let names = ["Anna", "Alex", "Brian", "Jack"]let count = names.countfor i in 0..<count { print("第 \(i + 1) 個(gè)人叫 \(names[i])") } // 第 1 個(gè)人叫 Anna // 第 2 個(gè)人叫 Alex // 第 3 個(gè)人叫 Brian // 第 4 個(gè)人叫 Jack
初始化空字符串,字符串可變性,字符串是值類型,連接字符串和字符(+,+=)。
使用字符,可通過(guò) for-in 循環(huán)來(lái)遍歷字符串,獲取字符串中每一個(gè)字符的值。
字符串插值是一種構(gòu)建新字符串的方式,可以在其中包含常量、變量、字面量和表達(dá)式??梢栽谝延凶址胁迦氤A?、變量、字面量和表達(dá)式從而形成更長(zhǎng)的字符串。
Swift 提供了三種方式來(lái)比較文本值:字符串字符相等、前綴相等和后綴相等。
示例:
// 多行字符串字面量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è)字符串其實(shí)是一樣的let singleLineString = "These are the same."let multilineString = """ These are the same. """// 字符串插值let multiplier = 3let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"// message 是 "3 times 2.5 is 7.5"// 計(jì)算字符數(shù)量 var word = "cafe"print("the number of characters in \(word) is \(word.count)") // 打印輸出“the number of characters in cafe is 4” var emptyString = "" // 空字符串字面量 var anotherEmptyString = String() // 初始化方法 // 兩個(gè)字符串均為空并等價(jià)。let catCharacters: [Character] = ["C", "a", "t", "!"]let catString = String(catCharacters)print(catString) // 打印輸出:“Cat!”
Swift 語(yǔ)言提供數(shù)組(Array)、集合(Set)和字典(Dictionary)三種基本的集合類型用來(lái)存儲(chǔ)集合數(shù)據(jù)。數(shù)組是有序數(shù)據(jù)的集。集合是無(wú)序無(wú)重復(fù)數(shù)據(jù)的集。字典是無(wú)序的鍵值對(duì)的集。
數(shù)組使用有序列表存儲(chǔ)同一類型的多個(gè)值。相同的值可以多次出現(xiàn)在一個(gè)數(shù)組的不同位置中。
集合用來(lái)存儲(chǔ)相同類型并且沒(méi)有確定順序的值。當(dāng)集合元素順序不重要時(shí)或者希望確保每個(gè)元素只出現(xiàn)一次時(shí)可以使用集合而不是數(shù)組。
集合操作,可以高效地完成集合的一些基本操作,比如把兩個(gè)集合組合到一起,判斷兩個(gè)集合共有元素,或者判斷兩個(gè)集合是否全包含,部分包含或者不相交。
字典是一種無(wú)序的集合,它存儲(chǔ)的是鍵值對(duì)之間的關(guān)系,其所有鍵的值需要是相同的類型,所有值的類型也需要相同。每個(gè)值(value)都關(guān)聯(lián)唯一的鍵(key),鍵作為字典中這個(gè)值數(shù)據(jù)的標(biāo)識(shí)符。
示例:
// 集合 var someInts = [Int]()print("someInts is of type [Int] with \(someInts.count) items.") // 打印“someInts is of type [Int] with 0 items.” var threeDoubles = Array(repeating: 0.0, count: 3) // threeDoubles 是一種 [Double] 數(shù)組,等價(jià)于 [0.0, 0.0, 0.0] var anotherThreeDoubles = Array(repeating: 2.5, count: 3) // anotherThreeDoubles 被推斷為 [Double],等價(jià)于 [2.5, 2.5, 2.5] var sixDoubles = threeDoubles + anotherThreeDoubles // sixDoubles 被推斷為 [Double],等價(jià)于 [0.0, 0.0, 0.0, 2.5, 2.5, 2.5] // enumerated() 方法遍歷數(shù)組 var shoppingList: [String] = ["Eggs", "Milk"]for (index, value) in shoppingList.enumerated() { print("Item \(String(index + 1)): \(value)") }
像 if 語(yǔ)句一樣,guard 的執(zhí)行取決于一個(gè)表達(dá)式的布爾值。我們可以使用 guard 語(yǔ)句來(lái)要求條件必須為真時(shí),以執(zhí)行 guard 語(yǔ)句后的代碼。不同于 if 語(yǔ)句,一個(gè) guard 語(yǔ)句總是有一個(gè) else 從句,如果條件不為真則執(zhí)行 else 從句中的代碼。
Swift 內(nèi)置支持檢查 API 可用性,編譯器使用 SDK 中的可用信息來(lái)驗(yàn)證我們的代碼中使用的所有 API 在項(xiàng)目指定的部署目標(biāo)上是否可用。如果我們嘗試使用一個(gè)不可用的 API,Swift 會(huì)在編譯時(shí)報(bào)錯(cuò)。
示例:
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") } // repeat-while 循環(huán)的一般格式 repeat { statements } while condition // 提前退出 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).") } greet(person: ["name": "John"]) // 輸出“Hello John!” // 輸出“I hope the weather is nice near you.” greet(person: ["name": "Jane", "location": "Cupertino"]) // 輸出“Hello Jane!” // 輸出“I hope the weather is nice in Cupertino.”
可選元組返回類型。
定義一個(gè)輸入輸出參數(shù)時(shí),在參數(shù)定義前加 inout 關(guān)鍵字。
示例:
// 函數(shù) func greet(person: String) -> String { let greeting = "Hello, " + person + "!" return greeting } func greet(person: String, from hometown: String) -> String { return "Hello \(person)! Glad you could visit from \(hometown)."}print(greet(person: "Bill", from: "Cupertino")) // 打印“Hello Bill! Glad you could visit from Cupertino.” // 可選元組返回類型 func minMax(array: [Int]) -> (min: Int, max: Int)? { if array.isEmpty { return nil } var currentMin = array[0] var currentMax = array[0] for value in array[1..<array.count] { if value < currentMin { currentMin = value } else if value > currentMax { currentMax = value } } return (currentMin, currentMax) } // 隱式返回的函數(shù) func greeting(for person: String) -> String { "Hello, " + person + "!"}print(greeting(for: "Dave")) // 打印 "Hello, Dave! // 參數(shù)標(biāo)簽 func greet(person: String, from hometown: String) -> String { return "Hello \(person)! Glad you could visit from \(hometown)." } print(greet(person: "Bill", from: "Cupertino")) // 打印“Hello Bill! Glad you could visit from Cupertino.”
閉包是自包含的函數(shù)代碼塊,可以在代碼中被傳遞和使用。與一些編程語(yǔ)言中的匿名函數(shù)(Lambdas)比較相似。
如果你需要將一個(gè)很長(zhǎng)的閉包表達(dá)式作為最后一個(gè)參數(shù)傳遞給函數(shù),將這個(gè)閉包替換成為尾隨閉包的形式很有用。
閉包可以在其被定義的上下文中捕獲常量或變量。即使定義這些常量和變量的原作用域已經(jīng)不存在,閉包仍然可以在閉包函數(shù)體內(nèi)引用和修改這些值。
示例:
// 閉包表達(dá)式語(yǔ)法 { (parameters) -> return type in statements } // 尾隨閉包let digitNames = [ 0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four", 5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"]let numbers = [16, 58, 510]let strings = numbers.map { (number) -> String in var number = number var output = "" repeat { output = digitNames[number % 10]! + output number /= 10 } while number > 0 return output } // strings 常量被推斷為字符串類型數(shù)組,即 [String] // 其值為 ["OneSix", "FiveEight", "FiveOneZero"] // 值捕獲 func makeIncrementer(forIncrement amount: Int) -> () -> Int { var runningTotal = 0 func incrementer() -> Int { runningTotal += amount return runningTotal } return incrementer } // 自動(dòng)閉包,延遲求值 var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]print(customersInLine.count) // 打印出“5”let customerProvider = { customersInLine.remove(at: 0) }print(customersInLine.count) // 打印出“5”print("Now serving \(customerProvider())!") // Prints "Now serving Chris!"print(customersInLine.count) // 打印出“4”
使用 enum 關(guān)鍵詞來(lái)創(chuàng)建枚舉并且把它們的整個(gè)定義放在一對(duì)大括號(hào)內(nèi)。
可以定義 Swift 枚舉來(lái)存儲(chǔ)任意類型的關(guān)聯(lián)值,每個(gè)枚舉成員的關(guān)聯(lián)值類型可以各不相同。
示例:
// 枚舉語(yǔ)法 enum SomeEnumeration { // 枚舉定義放在這里 } enum CompassPoint { case north case south case east case west } enum Planet { case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune }let somePlanet = Planet.earth switch somePlanet {case .earth: print("Mostly harmless") default: print("Not a safe place for humans") } // 打印“Mostly harmless” // 關(guān)聯(lián)值 enum Barcode { case upc(Int, Int, Int, Int) case qrCode(String) } var productBarcode = Barcode.upc(8, 85909, 51226, 3) productBarcode = .qrCode("ABCDEFGHIJKLMNOP") switch productBarcode {case let .upc(numberSystem, manufacturer, product, check): print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")case let .qrCode(productCode): print("QR code: \(productCode).") } // 打印“QR code: ABCDEFGHIJKLMNOP.” // 遞歸枚舉 indirect enum ArithmeticExpression { 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)) // (5 + 4) * 2 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) } }print(evaluate(product)) // 打印“18”
結(jié)構(gòu)體和類作為一種通用而又靈活的結(jié)構(gòu),成為了人們構(gòu)建代碼的基礎(chǔ)。你可以使用定義常量、變量和函數(shù)的語(yǔ)法,為你的結(jié)構(gòu)體和類定義屬性、添加方法。
示例:
// 類和結(jié)構(gòu)體 struct SomeStructure { // 在這里定義結(jié)構(gòu)體 } class SomeClass { // 在這里定義類 } struct Resolution { var width = 0 var height = 0 } class VideoMode { var resolution = Resolution() var interlaced = false var frameRate = 0.0 var name: String? }
屬性將值與特定的類、結(jié)構(gòu)體或枚舉關(guān)聯(lián)。存儲(chǔ)屬性會(huì)將常量和變量存儲(chǔ)為實(shí)例的一部分,而計(jì)算屬性則是直接計(jì)算(而不是存儲(chǔ))值。計(jì)算屬性可以用于類、結(jié)構(gòu)體和枚舉,而存儲(chǔ)屬性只能用于類和結(jié)構(gòu)體。
屬性觀察器監(jiān)控和響應(yīng)屬性值的變化,每次屬性被設(shè)置值的時(shí)候都會(huì)調(diào)用屬性觀察器,即使新值和當(dāng)前值相同的時(shí)候也不例外。
willSet 在新的值被設(shè)置之前調(diào)用
didSet 在新的值被設(shè)置之后調(diào)用
屬性包裝器在管理屬性如何存儲(chǔ)和定義屬性的代碼之間添加了一個(gè)分隔層。
類型屬性也是通過(guò)點(diǎn)運(yùn)算符來(lái)訪問(wèn)。但是,類型屬性是通過(guò)類型本身來(lái)訪問(wèn),而不是通過(guò)實(shí)例。
示例:
// 屬性 struct Point { var x = 0.0, y = 0.0 } struct Size { var width = 0.0, height = 0.0 } struct Rect { var origin = Point() var size = Size() //存儲(chǔ)屬性 var center: Point { //計(jì)算型屬性 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 square = Rect(origin: Point(x: 0.0, y: 0.0), size: Size(width: 10.0, height: 10.0))let initialSquareCenter = square.center square.center = Point(x: 15.0, y: 15.0)print("square.origin is now at (\(square.origin.x), \(square.origin.y))") // 打印“square.origin is now at (10.0, 10.0)” // 屬性包裝器 @propertyWrapper struct TwelveOrLess { private var number = 0 var wrappedValue: Int { get { return number } set { number = min(newValue, 12) } } }
方法是與某些特定類型相關(guān)聯(lián)的函數(shù)。
類、結(jié)構(gòu)體、枚舉都可以定義實(shí)例方法;實(shí)例方法為給定類型的實(shí)例封裝了具體的任務(wù)與功能。
類、結(jié)構(gòu)體、枚舉也可以定義類型方法;類型方法與類型本身相關(guān)聯(lián)。
示例:
// 方法 class Counter { var count = 0 func increment() { count += 1 } func increment(by amount: Int) { count += amount } func reset() { count = 0 } }
下標(biāo)可以定義在類、結(jié)構(gòu)體和枚舉中,是訪問(wèn)集合、列表或序列中元素的快捷方式
subscript(index: Int) -> Int { get { // 返回一個(gè)適當(dāng)?shù)?nbsp;Int 類型的值 } set(newValue) { // 執(zhí)行適當(dāng)?shù)馁x值操作 } } // 示例 struct TimesTable { let multiplier: Int subscript(index: Int) -> Int { return multiplier * index } }let threeTimesTable = TimesTable(multiplier: 3)print("six times three is \(threeTimesTable[6])") // 打印“six times three is 18” var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4] numberOfLegs["bird"] = 2 // 類型下標(biāo) enum Planet: Int { case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune static subscript(n: Int) -> Planet { return Planet(rawValue: n)! } }let mars = Planet[4]print(mars)
不繼承于其它類的類,稱之為基類。
示例:
// 繼承 class SomeClass: SomeSuperclass { // 這里是子類的定義 } class Vehicle { var currentSpeed = 0.0 var description: String { return "traveling at \(currentSpeed) miles per hour" } func makeNoise() { // 什么也不做——因?yàn)檐囕v不一定會(huì)有噪音 } } class Car: Vehicle { var gear = 1 override var description: String { return super.description + " in gear \(gear)" } } class AutomaticCar: Car { override var currentSpeed: Double { didSet { gear = Int(currentSpeed / 10.0) + 1 } } }
構(gòu)造過(guò)程是使用類、結(jié)構(gòu)體或枚舉類型的實(shí)例之前的準(zhǔn)備過(guò)程。
構(gòu)造器可以通過(guò)調(diào)用其它構(gòu)造器來(lái)完成實(shí)例的部分構(gòu)造過(guò)程。這一過(guò)程稱為構(gòu)造器代理,它能避免多個(gè)構(gòu)造器間的代碼重復(fù)。
Swift 為類類型提供了兩種構(gòu)造器來(lái)確保實(shí)例中所有存儲(chǔ)型屬性都能獲得初始值,它們被稱為指定構(gòu)造器和便利構(gòu)造器。
可以在一個(gè)類,結(jié)構(gòu)體或是枚舉類型的定義中,添加一個(gè)或多個(gè)可失敗構(gòu)造器。其語(yǔ)法為在 init 關(guān)鍵字后面添加問(wèn)號(hào)(init?)。
必要構(gòu)造器,在類的構(gòu)造器前添加 required 修飾符表明所有該類的子類都必須實(shí)現(xiàn)該構(gòu)造器。
示例:
// 構(gòu)造過(guò)程init() { // 在此處執(zhí)行構(gòu)造過(guò)程 } struct Fahrenheit { var temperature: Double init() { temperature = 32.0 } } var f = Fahrenheit()print("The default temperature is \(f.temperature)° Fahrenheit") // 打印“The default temperature is 32.0° Fahrenheit” struct Color { let red, green, blue: Double init(red: Double, green: Double, blue: Double) { self.red = red self.green = green self.blue = blue } init(white: Double) { red = white green = white blue = white } }
析構(gòu)器只適用于類類型,當(dāng)一個(gè)類的實(shí)例被釋放之前,析構(gòu)器會(huì)被立即調(diào)用。析構(gòu)器用關(guān)鍵字 deinit 來(lái)標(biāo)示,類似于構(gòu)造器要用 init 來(lái)標(biāo)示。
Swift 會(huì)自動(dòng)釋放不再需要的實(shí)例以釋放資源。
示例:
// 析構(gòu)過(guò)程 deinit { // 執(zhí)行析構(gòu)過(guò)程 } class Bank { static var coinsInBank = 10_000 static func distribute(coins numberOfCoinsRequested: Int) -> Int { let numberOfCoinsToVend = min(numberOfCoinsRequested, coinsInBank) coinsInBank -= numberOfCoinsToVend return numberOfCoinsToVend } static func receive(coins: Int) { coinsInBank += coins } } class Player { var coinsInPurse: Int init(coins: Int) { coinsInPurse = Bank.distribute(coins: coins) } func win(coins: Int) { coinsInPurse += Bank.distribute(coins: coins) } deinit { Bank.receive(coins: coinsInPurse) } }
可選鏈?zhǔn)秸{(diào)用是一種可以在當(dāng)前值可能為 nil 的可選值上請(qǐng)求和調(diào)用屬性、方法及下標(biāo)的方法。
通過(guò)在想調(diào)用的屬性、方法,或下標(biāo)的可選值后面放一個(gè)問(wèn)號(hào)(?),可以定義一個(gè)可選鏈。類似在可選值后面放一個(gè)嘆號(hào)(!)來(lái)強(qiáng)制展開它的值。它們的主要區(qū)別在于當(dāng)可選值為空時(shí)可選鏈?zhǔn)秸{(diào)用只會(huì)調(diào)用失敗,然而強(qiáng)制展開將會(huì)觸發(fā)運(yùn)行時(shí)錯(cuò)誤。
示例:
class Person { var residence: Residence? } class Residence { var numberOfRooms = 1 }let john = Person()let roomCount = john.residence!.numberOfRooms // 這會(huì)引發(fā)運(yùn)行時(shí)錯(cuò)誤if let roomCount = john.residence?.numberOfRooms { print("John's residence has \(roomCount) room(s).") } else { print("Unable to retrieve the number of rooms.") } // 打印“Unable to retrieve the number of rooms.” john.residence = Residence()if let roomCount = john.residence?.numberOfRooms { print("John's residence has \(roomCount) room(s).") } else { print("Unable to retrieve the number of rooms.") } // 打印“John's residence has 1 room(s).”
錯(cuò)誤處理(Error handling) 是響應(yīng)錯(cuò)誤以及從錯(cuò)誤中恢復(fù)的過(guò)程。Swift 在運(yùn)行時(shí)提供了拋出、捕獲、傳遞和操作可恢復(fù)錯(cuò)誤(recoverable errors)的一等支持。
在 Swift 中,錯(cuò)誤用遵循 Error 協(xié)議的類型的值來(lái)表示。
Swift 中有 4 種處理錯(cuò)誤的方式。可以把函數(shù)拋出的錯(cuò)誤傳遞給調(diào)用此函數(shù)的代碼(throws)、用 do-catch 語(yǔ)句處理錯(cuò)誤、將錯(cuò)誤作為可選類型處理(try?)、或者斷言此錯(cuò)誤根本不會(huì)發(fā)生(try!)。
defer 語(yǔ)句將代碼的執(zhí)行延遲到當(dāng)前的作用域退出之前。
示例:
// 錯(cuò)誤處理 enum VendingMachineError: Error { case invalidSelection //選擇無(wú)效 case insufficientFunds(coinsNeeded: Int) //金額不足 case outOfStock //缺貨 } throw VendingMachineError.insufficientFunds(coinsNeeded: 5) var vendingMachine = VendingMachine() vendingMachine.coinsDeposited = 8do { try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine) print("Success! Yum.") } catch VendingMachineError.invalidSelection { print("Invalid Selection.") } catch VendingMachineError.outOfStock { print("Out of Stock.") } catch VendingMachineError.insufficientFunds(let coinsNeeded) { print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.") } catch { print("Unexpected error: \(error).") } // 打印“Insufficient funds. Please insert an additional 2 coins.” // 指定清理操作 func processFile(filename: String) throws { if exists(filename) { let file = open(filename) defer { close(file) } while let line = try file.readline() { // 處理文件。 } // close(file) 會(huì)在這里被調(diào)用,即作用域的最后。 } }
類型轉(zhuǎn)換在 Swift 中使用 is 和 as 操作符實(shí)現(xiàn)。這兩個(gè)操作符分別提供了一種簡(jiǎn)單達(dá)意的方式去檢查值的類型或者轉(zhuǎn)換它的類型。
可以將類型轉(zhuǎn)換用在類和子類的層次結(jié)構(gòu)上,檢查特定類實(shí)例的類型并且轉(zhuǎn)換這個(gè)類實(shí)例的類型成為這個(gè)層次結(jié)構(gòu)中的其他類型。
Swift 為不確定類型提供了兩種特殊的類型別名:
Any 可以表示任何類型,包括函數(shù)類型。
AnyObject 可以表示任何類類型的實(shí)例。
示例:
// 類型轉(zhuǎn)換 // 一個(gè)基類 MediaItem class MediaItem { var name: String init(name: String) { self.name = name } } class Movie: MediaItem { var director: String init(name: String, director: String) { self.director = director super.init(name: name) } } class Song: MediaItem { var artist: String init(name: String, artist: String) { self.srtist = artist super.init(name: name) } }let library = [ Movie(name: "Casablanca", director: "Micheal Curtiz"), Song(name: "Blue Suede Shose", artist: "Elvis Presley"), Movie(name: "Citizen Kane", director: "Orson Wells"), Song(name: "The One And Only", artist: "Chesney Hawkes"), Song(name: "Never Gonna Give You Up", artist: "Rick Astley") ] var movieCount = 0 var songCount = 0for item in library { if item is Movie { movieCount += 1 } else if item is Song { songCount += 1 } }print("Media library contains \(movieCount) movies and \(songCount)") // 打印“Media library contains 2 movies and 3 songs”for item in library { if let movie = item as? Movie { print("Movie: \(movie.name), dir. \(movie.director)") } else if let song = item as? Song { print("Song: \(song.name), by \(song.artist)") } } // Movie: Casablanca, dir. Michael Curtiz // Song: Blue Suede Shoes, by Elvis Presley // Movie: Citizen Kane, dir. Orson Welles // Song: The One And Only, by Chesney Hawkes // Song: Never Gonna Give You Up, by Rick Astley
Swift 允許定義嵌套類型,可以在支持的類型中定義嵌套的枚舉、類和結(jié)構(gòu)體。
要在一個(gè)類型中嵌套另一個(gè)類型,將嵌套類型的定義寫在其外部類型的 {} 內(nèi),而且可以根據(jù)需要定義多級(jí)嵌套。
示例:
// 嵌套類型 stuct BlackjackCard { // 嵌套的 Suit 枚舉 enum Suit: Character { case spades = "1", hearts = "2", diamonds = "3", clubs = "4" } // 嵌套的 Rank 枚舉 enum Rank: Int { case two = 2, three, four, five, six, seven, eight, nine, ten case jack, queen, king, ace struct Values { let first: Int, second: Int? } var values: Values { switch self { case .ace: return Values(first: 1, second: 11) case .jack, .queen, .king: return Values(first: 10, second: nil) default: return Values(first: self.rawValue, second: nil) } } } // BlackjackCard 的屬性和方法 let rank: Rank, suit: Suit var description: String { var output = "suit is \(suit.rawValue)," output += " value is \(rank.values.first)" if let second = rank.values.second { output += " or \(second)" } return output } }let theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades)print("theAceOfSpades: \(theAceOfSpades.description)") // 打印“theAceOfSpades: suit is 1, value is 1 or 11”let heartsSymbol = BlackjackCard.Suit.hearts.rawValue // 2
擴(kuò)展可以給一個(gè)現(xiàn)有的類,結(jié)構(gòu)體,枚舉,還有協(xié)議添加新的功能。
Swift 中的擴(kuò)展可以:
添加計(jì)算型實(shí)例屬性和計(jì)算型類屬性
定義實(shí)例方法和類方法
提供新的構(gòu)造器
定義下標(biāo)
定義和使用新的嵌套類型
使已經(jīng)存在的類型遵循(conform)一個(gè)協(xié)議
擴(kuò)展語(yǔ)法:
extension SomeType { // 在這里給 SomeType 添加新的功能 }
擴(kuò)展可以給現(xiàn)有類型添加計(jì)算型實(shí)例屬性和計(jì)算型類屬性。
擴(kuò)展可以給現(xiàn)有的類型添加新的構(gòu)造器。
擴(kuò)展可以給現(xiàn)有類型添加新的實(shí)例方法和類方法。
擴(kuò)展可以給現(xiàn)有的類型添加新的下標(biāo)。
擴(kuò)展可以給現(xiàn)有的類,結(jié)構(gòu)體,還有枚舉添加新的嵌套類型。
示例:
// 擴(kuò)展的語(yǔ)法 extension SomeType { // 在這里給 SomeType 添加新的功能 } // 添加一個(gè)或多個(gè)協(xié)議 extension SomeType: SomeProtocol, AnotherProtocol { // 協(xié)議所需要的實(shí)現(xiàn)寫在這里 } struct Size { var width = 0.0, height = 0.0 } struct Point { var x = 0.0, y = 0.0 } struct Rect { var origin = Point() var size = Size() } extension Rect { init(center: Point, size: Size) { let originX = center.x - (size.width / 2) let originY = center.y - (size.height / 3) self.init(origin: Point(x: originX, y: originY), size: size) } }let centerRect = Rect(center: Point(x: 4.0, y: 4.0), size: Size(width: 3.0, height: 3.0)) // centerRect 的 origin 是 (2.5, 2.5) 并且它的 size 是 (3.0, 3.0) extension Int { func repetitions(task: () -> Void) { for _ in 0..<self { task() } } } 3.repetitions { print("Hello!") } // Hello! // Hello! // Hello! extension Int { mutating func square() { self = self * self } } var somtInt = 3 someInt.square() // someInt 現(xiàn)在是9
協(xié)議定義了一個(gè)藍(lán)圖,規(guī)定了用來(lái)實(shí)現(xiàn)某一特定任務(wù)或者功能的方法、屬性,以及其他需要的東西。
類、結(jié)構(gòu)體或枚舉都可以遵循協(xié)議,并為協(xié)議定義的這些要求提供具體實(shí)現(xiàn)。
協(xié)議語(yǔ)法
protocol SomeProtocol { // 這里是協(xié)議的定義部分 }
協(xié)議可以要求遵循協(xié)議的類型提供特定名稱和類型的實(shí)例屬性或類型屬性。
協(xié)議可以要求遵循協(xié)議的類型實(shí)現(xiàn)某些指定的實(shí)例方法或類方法。
在值類型(即結(jié)構(gòu)體和枚舉)的實(shí)例方法中,將 mutating 關(guān)鍵字作為方法的前綴,寫在 func 關(guān)鍵字之前,表示可以在該方法中修改它所屬的實(shí)例以及實(shí)例的任意屬性的值。
協(xié)議可以要求遵循協(xié)議的類型實(shí)現(xiàn)指定的構(gòu)造器。
委托是一種設(shè)計(jì)模式,它允許類或結(jié)構(gòu)體將一些需要它們負(fù)責(zé)的功能委托給其他類型的實(shí)例。
示例:
// 協(xié)議語(yǔ)法 protocol SomeProtocol { // 這里是協(xié)議的定義部分 } struct SomeStructure: FirstProtocol, AnotherProtocol { // 這里是結(jié)構(gòu)體的定義部分 } class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol { // 這里是類的定義部分 } protocol SomeProtocol { var mustBeSettable: Int { get set } var doesNotNeedToBeSettable: Int { get } } protocol AnotherProtocol { static var someTypeProperty: Int { get set } } protocol FullyNamed { var fullName: String { get } } struct person: FullyNamed { var fullName: String }let john = Person(fullName: "John Appleseed") // john.fullName 為 "John Appleseed"class Starship: FullyNamed { var prefix: String? var name: String init(name: String, prefix: String? = nil) { self.name = name self.prefix = prefix } var fullName: String { return (prefix != nil ? prefix! + " " : "") + name } } var ncc1701 = Starship(name: "Enterprise", prefix: "USS") // ncc1701.fullName 為 "USS Enterprise"
泛型代碼讓你能根據(jù)自定義的需求,編寫出適用于任意類型的、靈活可復(fù)用的函數(shù)及類型。
你可避免編寫重復(fù)的代碼,而是用一種清晰抽象的方式來(lái)表達(dá)代碼的意圖。
示例:
func swapTwoInts(_ a: inout Int, _ b: inout Int) { let temporaryA = a a = b b = temporaryA } func swapTwoValues<T>(_ a: inout T, _ b: inout T) { let temporaryA = a a = b b = temporaryA } func swapTwoInts(_ a: inout Int, _ b: inout Int) func swapTwoValues<T>(_ a: inout T, _ b: inout T) var someInt = 3 var anotherInt = 107 swapTwoValues(&someInt, &anotherInt) // someInt 現(xiàn)在是 107,anotherInt 現(xiàn)在是 3 var someString = "hello"var anotherString = "world"swapTwoValues(&someString, &anotherString) // someString 現(xiàn)在是“world”,anotherString 現(xiàn)在是“hello”
具有不透明返回類型的函數(shù)或方法會(huì)隱藏返回值的類型信息。
函數(shù)不再提供具體的類型作為返回類型,而是根據(jù)它支持的協(xié)議來(lái)描述返回值。
在處理模塊和調(diào)用代碼之間的關(guān)系時(shí),隱藏類型信息非常有用,因?yàn)榉祷氐牡讓訑?shù)據(jù)類型仍然可以保持私有。
不透明類型和泛型相反。不透明類型允許函數(shù)實(shí)現(xiàn)時(shí),選擇一個(gè)與調(diào)用代碼無(wú)關(guān)的返回類型。
如果函數(shù)中有多個(gè)地方返回了不透明類型,那么所有可能的返回值都必須是同一類型。返回不透明類型和返回協(xié)議類型主要區(qū)別,就在于是否需要保證類型一致性。
一個(gè)不透明類型只能對(duì)應(yīng)一個(gè)具體的類型,即便函數(shù)調(diào)用者并不能知道是哪一種類型;協(xié)議類型可以同時(shí)對(duì)應(yīng)多個(gè)類型,只要它們都遵循同一協(xié)議。
示例:
protocol Shape { func draw() -> String } struct Triangle: Shape { var size: Int func draw() -> String { var result = [String]() for length in 1...size { result.append(String(repeating: "*", count: length)) } return result.joined(separator: "\n") } }let smallTriangle = Triangle(size: 3)print(smallTriangle.draw()) // * // ** // *** struct FlippedShape<T: Shape>: Shape { var shape: T func draw() -> String { let lines = shape.draw().split(separator: "\n") return lines.reversed().joined(separator: "\n") } }let flippedTriangle = FlippedShape(shape: smallTriangle)print(flippedTriangle.draw()) // *** // ** // *
Swift 使用自動(dòng)引用計(jì)數(shù)(ARC)機(jī)制來(lái)跟蹤和管理你的應(yīng)用程序的內(nèi)存。
如果兩個(gè)類實(shí)例互相持有對(duì)方的強(qiáng)引用,因而每個(gè)實(shí)例都讓對(duì)方一直存在,就是這種情況。這就是所謂的循環(huán)強(qiáng)引用。
Swift提供了兩種辦法用來(lái)解決你在使用類的屬性時(shí)所遇到的循環(huán)強(qiáng)引用問(wèn)題:弱引用(weak reference)和無(wú)主引用(unowned reference)。
聲明屬性或者變量時(shí),在前面加上 weak 關(guān)鍵字表明這是一個(gè)弱引用。
聲明屬性或者變量時(shí),在前面加上關(guān)鍵字 unowned 表示這是一個(gè)無(wú)主引用。
示例:
// 自動(dòng)引用計(jì)數(shù)實(shí)踐 class Person { let name: String init(name: String) { self.name = name print("\(name) is being initialized") } deinit { print("\(name) is being deinitialized") } } var reference1: Person? var reference2: Person? var reference3: Person? reference1 = Person(name: "John Appleseed") // 打印“John Appleseed is being initialized” reference2 = reference1 reference3 = reference1 reference1 = nil reference2 = nil reference3 = nil // 打印“John Appleseed is being deinitialized” // 循環(huán)強(qiáng)引用 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 } var tenant: Person? deinit { print("Apartment \(unit) is being deinitialized") } } var john: Person? var unit4A: Apartment? john = Person(name: "John Appleseed") unit4A = Apartment(unit: "4A") john = nil unit4A = nil // 弱引用 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? deinit { print("Apartment \(unit) is being deinitialized") } } var john: Person? var unit4A: Apartment? john = Person(name: "John Appleseed") unit4A = Apartment(unit: "4A") john!.apartment = unit4A unit4A!.tenant = john john = nil // 打印“John Appleseed is being deinitialized”
默認(rèn)情況下,Swift 會(huì)阻止你代碼里不安全的行為。
示例:
func balance(_ x: inout Int, _ y: inout Int) { let sum = x + y x = sum / 2 y = sum - x } var playerOneScore = 42 var playerTwoScore = 30 balance(&playerOneScore, &playerTwoScore) // 正常 balance(&playerOneScore, &playerOneScore) // 錯(cuò)誤:playerOneScore 訪問(wèn)沖突
訪問(wèn)控制可以限定其它源文件或模塊對(duì)你的代碼的訪問(wèn)。
open 和 public 級(jí)別可以讓實(shí)體被同一模塊源文件中的所有實(shí)體訪問(wèn),在模塊外也可以通過(guò)導(dǎo)入該模塊來(lái)訪問(wèn)源文件里的所有實(shí)體。通常情況下,你會(huì)使用 open 或 public 級(jí)別來(lái)指定框架的外部接口。
internal 級(jí)別讓實(shí)體被同一模塊源文件中的任何實(shí)體訪問(wèn),但是不能被模塊外的實(shí)體訪問(wèn)。通常情況下,如果某個(gè)接口只在應(yīng)用程序或框架內(nèi)部使用,就可以將其設(shè)置為 internal 級(jí)別。
fileprivate 限制實(shí)體只能在其定義的文件內(nèi)部訪問(wèn)。如果功能的部分實(shí)現(xiàn)細(xì)節(jié)只需要在文件內(nèi)使用時(shí),可以使用 fileprivate 來(lái)將其隱藏。
private 限制實(shí)體只能在其定義的作用域,以及同一文件內(nèi)的 extension 訪問(wèn)。如果功能的部分細(xì)節(jié)只需要在當(dāng)前作用域內(nèi)使用時(shí),可以使用 private 來(lái)將其隱藏。
open 為最高訪問(wèn)級(jí)別(限制最少),private 為最低訪問(wèn)級(jí)別(限制最多)。
open 只能作用于類和類的成員,它和 public 的區(qū)別主要在于 open 限定的類和成員能夠在模塊外能被繼承和重寫。
示例:
public class SomePublicClass {} internal class SomeInternalClass {} fileprivate class SomeFilePrivateClass {} private class SomePrivateClass {} class SomeInternalClass {} // 隱式 internal var someInternalConstant = 0 // 隱式 internal public class SomePublicClass { // 顯式 public 類 public var somePublicProperty = 0 // 顯式 public 類成員 var someInternalProperty = 0 // 隱式 internal 類成員 fileprivate func someFilePrivateMethod() {} // 顯式 fileprivate 類成員 private func somePrivateMethod() {} // 顯式 private 類成員 } class SomeInternalClass { // 隱式 internal 類 var someInternalProperty = 0 // 隱式 internal 類成員 fileprivate func someFilePrivateMethod() {} // 顯式 fileprivate 類成員 private func somePrivateMethod() {} // 顯式 private 類成員 } fileprivate class SomeFilePrivateClass { // 顯式 fileprivate 類 func someFilePrivateMethod() {} // 隱式 fileprivate 類成員 private func somePrivateMethod() {} // 顯式 private 類成員 } private class SomePrivateClass { // 顯式 private 類 func somePrivateMethod() {} // 隱式 private 類成員 }
Swift還提供了數(shù)種可以對(duì)數(shù)值進(jìn)行復(fù)雜運(yùn)算的高級(jí)運(yùn)算符。它們包含了位運(yùn)算符和移位運(yùn)算符。
示例:
let initialBits: UInt8 = 0b00001111let invertedBits = ~initialBits // 等于 0b11110000 var potentialOverflow = Int16.max // potentialOverflow 的值是 32767,這是 Int16 能容納的最大整數(shù) potentialOverflow += 1 // 這里會(huì)報(bào)錯(cuò) 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) } }let vector = Vector2D(x: 3.0, y: 1.0)let anotherVector = Vector2D(x: 2.0, y: 4.0)let combinedVector = vector + anotherVector // combinedVector 是一個(gè)新的 Vector2D 實(shí)例,值為 (5.0, 5.0)
到此,相信大家對(duì)“什么是Swift語(yǔ)法”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。