繼續學習Swift文檔,從上一章節:開篇 ,咱們瞭解Swift基本的知識點,如今咱們仍是從詳細的基礎知識開始,不要認爲基礎知識不重要,這是掌握一門開發語言的基本。因爲篇幅較長,這裏分篇來記錄,接下來,開始吧!html
若是你已經掌握了Swift的基礎,那麼請參閱下一章節:基本操做web
Swift是一門新的針對iOS、macOS、watchOS和tvOS開發的編程語言。儘管如此,根據您使用C和Objective-C進行開發的經驗,您將熟悉Swift的許多部分。編程
Swift提供了本身版本的全部基本C和Objective-C類型,包括Int對應整型,Double和Float對應浮點類型,Bool對應布爾類型,和String對應文本數據。Swift還提供了三種主要收藏類型的強大版本,Array,Set和Dictionary,定義在 Collection Types.swift
像C同樣,Swift使用變量來存儲和經過一個標識名稱引用值。Swift還大量使用了不能更改值的變量。這些被稱爲常量,比c中的常量功能強大得多。當你處理不須要更改的值時,在Swift中使用常量使代碼更安全、更清晰。安全
除了熟悉的類型,Swift還引入了Objective-C中沒有的高級類型,好比元組。元組使您可以建立和傳遞值分組。可使用元組將函數中的多個值做爲一個複合值返回。bash
Swift還引入了可選類型,用於處理缺乏值的狀況。可選值要麼說「有一個值,它等於x」,要麼說「根本沒有值」。使用可選值相似於在Objective-C中對指針使用nil,但它們適用於任何類型,而不只僅是類。option不只比Objective-C中的nil指針更安全、更有表現力,並且是Swift許多最強大功能的核心。服務器
Swift是一種類型安全的語言,這意味着該語言能夠幫助您清楚地瞭解代碼可使用的值的類型。若是您的部分代碼須要String,類型安全防止您錯誤地將其傳遞爲Int。一樣,類型安全能夠防止您意外地將可選String傳遞給須要非可選String的代碼段。類型安全能夠幫助您儘早捕獲和修復開發過程當中的錯誤。數據結構
常量和變量將名稱(如maximumnumberoflogintries或welcomeMessage)與特定類型的值(如數字10或字符串「Hello」)關聯起來。常量的值一旦設置就不能更改,而變量能夠在未來設置爲不一樣的值。app
常量額變量在使用前必須聲明。能夠用let關鍵字聲明常量,用var關鍵字聲明變量。下面是一個如何使用常量和變量來跟蹤用戶嘗試登陸的次數的例子:less
let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0
複製代碼
這段代碼意思是: 「定義一個maximumNumberOfLoginAttempts常量,並賦值爲10。定義一個currentLoginAttempt變量,並賦值爲0.」
在這個例子中,聲明瞭一個最大容許登陸次數的常量,由於這個最大值沒有被修改。當前登陸嘗試計數器被聲明爲一個變量,由於在每次登陸嘗試失敗後,該值必須遞增。
你能夠在一行裏聲明多個常量和多個變量,用逗號分隔:
var x = 0.0, y = 0.0, z = 0.0
複製代碼
注意 若是代碼中存儲的值不會改變,請始終使用let關鍵字將其聲明爲常量。變量只用於存儲須要更改的值。
當你聲明常量和變量時,能夠添加類型,這樣就能夠知道須要存儲的值的類型。經過在常量或變量名後面加上冒號、空格和要使用的類型名來編寫類型註釋。
這個示例爲一個名爲welcomeMessage的變量提供了一個類型註釋,以代表該變量能夠存儲字符串值:
var welcomeMessage: String
複製代碼
聲明中的冒號表示「…of type…」,所以上面的代碼能夠理解爲:
「定義一個名稱叫welcomeMessage的字符串變量。」
短語「of type String」意味着「能夠存儲任何字符串值」。把它看做是能夠存儲的「事物的類型」(或「事物的種類」)的意思。
welcomeMessage變量能夠設置爲任何字符串值:
welcomeMessage = "Hello"
複製代碼
你能夠在一行中定義多個相同類型的相關變量,用逗號分隔,最後的變量名後面有一個類型註釋:
var red, green, blue: Double
複製代碼
實際上,不多須要編寫類型註釋。若是在定義常量或變量時提供初始值,Swift幾乎老是能夠推斷該常量或變量使用的類型,如 類型安全和類型推斷 所述。在上面的welcomeMessage示例中,沒有提供初始值,所以welcomeMessage變量的類型是經過類型註釋指定的,而不是從初始值推斷出來的。
常量和變量的名稱支持幾乎全部字符,包括Unicode字符:
let π = 3.14159
let 你好 = "你好世界"
let 🐶🐮 = "dogcow"
複製代碼
常量個變量的名稱不能包含空格,數學符號,箭頭,私有Unicode標量值,或**-和box-drawing**字符。也不能以數字開頭,儘管數字能夠包含在名稱的其餘地方。
一旦聲明瞭一個某些類型的常量和變量,就不能聲明和它相同名稱的,或者改變它存儲的類型。儘管能夠將一個常量修改成變量或者一個變量修改成常量。
注意 若是您須要爲一個常量或變量提供與保留的Swift關鍵字相同的名稱,在使用該關鍵字做爲名稱時使用反引號(`)。可是,除非別無選擇,不然要避免使用關鍵字做爲名稱。
能夠將現有變量的值更改成另外一個兼容類型的值,例如:
var friendlyWelcome = "Hello!"
friendlyWelcome = "Bonjour!"
// friendlyWelcome is now "Bonjour!"
複製代碼
和變量不一樣的是,常量一旦設置了值,就不能再修改,若是強行修改會報錯:
let languageName = "Swift"
languageName = "Swift++"
// This is a compile-time error: languageName cannot be changed.
複製代碼
能夠經過**print(_:separator:terminator:)**函數打印常量或變量:
print(friendlyWelcome)
// Prints "Bonjour!"
複製代碼
**print(:separator:terminator:)**函數是一個全局函數,它將在適當的輸出中打印一個或多個值。在Xcode中,例如,**print(:separator:terminator:)**函數會在Xcode的控制檯上輸出打印的值。 separator和 terminator有默認值,所以當調用這個函數時能夠忽略它們。默認狀況下,函數經過添加換行符來終止它打印的行。若要打印值後不帶換行符,請傳遞一個空字符串做爲終止符--例如: print(someValue, terminator: "")。有關具備默認值的參數的信息,參閱 Default Parameter Values。
Swift使用字符串插值將常量或變量的名稱做爲佔位符包含在較長的字符串中,並提示Swift將其替換爲該常數或變量的當前值。用括號括起名字,在括號前面用反斜槓轉義:
print("The current value of friendlyWelcome is \(friendlyWelcome)")
// Prints "The current value of friendlyWelcome is Bonjour!"
複製代碼
注意 字符串插值可使用的全部選項在String Interpolation都有描述。
使用註釋將不可執行文本包含在代碼中,做爲對本身的提示或提醒。代碼編譯時,Swift編譯器會忽略註釋。
Swift中的註釋和c的很類似。單行註釋用雙斜槓(//):
// This is a comment.
複製代碼
多行只是能夠用/* ... */:
/* This is also a comment
but is written over multiple lines. */
複製代碼
與C中的多行註釋不一樣,Swift中的多行註釋能夠嵌套在其餘多行註釋中。您能夠經過啓動一個多行註釋塊,而後在第一個註釋塊中啓動第二個多行註釋來編寫嵌套註釋。而後關閉第二個區塊,而後關閉第一個區塊:
/* This is the start of the first multiline comment.
/* This is the second, nested multiline comment. */
This is the end of the first multiline comment. */
複製代碼
嵌套多行註釋使您可以快速而輕鬆地註釋掉大塊代碼,即便代碼已經包含多行註釋。
和許多其餘語言不一樣,Swift不須要在語句末尾寫分號,儘管你但願這樣作。然而,當將多個語句寫在同一行時,須要加分號分隔:
let cat = "🐱"; print(cat)
// Prints "🐱"
複製代碼
整數是沒有分數成分的整數,例如42和-23。整數能夠是有符號的(正、零或負)或無符號的(正或零)。
Swift提供8位、16位、32位和64位格式的有符號整數和無符號整數。這些整數遵循相似於C的命名約定,即8位無符號整數的類型爲UInt8, 32位有符號整數的類型爲Int32。與Swift中的全部類型同樣,這些整數類型的名稱都是大寫的。
您能夠訪問每一個整數類型的最小值和最大值及其min和max屬性:
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
複製代碼
這些屬性的值具備適當大小的數字類型(如上面示例中的UInt8),所以能夠在表達式中與其餘相同類型的值一塊兒使用。
在大多數狀況下,您不須要在代碼中選擇特定大小的整數。Swift提供了一個額外的整數類型Int,它與當前平臺的本地字大小相同:
除非你須要處理一個特定大小的整數,不然整數都要用Int定義。這有助於代碼的一致性和互操做性。即便在32位平臺上,Int能夠存儲的值在-2,147,483,648和2,147,483,647之間,這個範圍能夠用在大多數整數上了。
Swift也提供了無符號的整型,UInt,它與當前平臺的本地字大小相同:
注意 僅當您特別須要與平臺的本地字大小相同的無符號整數類型時,才使用UInt。若是不是這樣,則首選Int,即便已知要存儲的值是非負的。整數值一致地使用Int有助於代碼的互操做性,避免不一樣數字類型之間的轉換,並匹配整型類型推斷,如類型安全和類型推斷中所述。
浮點數是由小數部分組成的數,如3.1415九、0.1和-273.15。
與整型相比,浮點型能夠表明更大範圍的值,而且能夠存儲比整型更大或更小的數字。Swift提供了兩種帶符號的浮點數類型:
注意 Double的精度至少爲15位十進制數字,而Float的精度只有6位十進制數字。要使用的適當浮點類型取決於代碼中須要使用的值的性質和範圍。若是兩種類型都合適,則首選Double。
Swift是一種類型安全的語言,類型安全語言鼓勵您明確代碼可使用的值的類型。若是代碼的一部分須要字符串,則不能錯誤地將其傳遞爲Int。
由於Swift是類型安全的,它在編譯代碼時執行類型檢查,並將任何不匹配的類型標記爲錯誤。這使您可以在開發過程當中儘早捕獲和修復錯誤。
當您使用不一樣類型的值時,類型檢查能夠幫助您避免錯誤。可是,這並不意味着必須指定聲明的每一個常量和變量的類型。若是沒有指定所需值的類型,Swift會使用類型推斷來計算出適當的類型。類型推斷使編譯器在編譯代碼時可以經過檢查提供的值自動推斷特定表達式的類型。
因爲有了類型推斷,Swift須要的類型聲明要比C或Objective-C等語言少得多。常量和變量仍然是顯式類型的,可是指定它們的類型的大部分工做已經爲您完成了。
在聲明具備初始值的常量或變量時,類型推斷特別有用。這一般是經過在聲明常量或變量時爲其分配一個文字值(或文字)來實現的。(文字值是直接出如今源代碼中的值,例以下面示例中的42和3.14159。)
例如,若是你給一個新常量賦值爲42而沒有說明它是什麼類型,Swift推斷你但願這個常量是一個整型數,由於你用一個看起來像整數的數字初始化了它:
let meaningOfLife = 42
// meaningOfLife is inferred to be of type Int
複製代碼
一樣地,若是你沒有指定一個浮點型文字的類型,Swift推斷你想要建立一個Double:
let pi = 3.14159
// pi is inferred to be of type Double
複製代碼
在推斷浮點數類型時,Swift老是選擇Double(而不是Float)。
若是你在一個表達式中結合了整型和浮點型文字,Double類型會從上下文推斷出來:
let anotherPi = 3 + 0.14159
// anotherPi is also inferred to be of type Double
複製代碼
字面值3自己沒有顯式的類型,所以能夠從做爲加法的一部分的浮點字面值中推斷出適當的輸出類型Double。
整型文字能夠寫成:
全部這些字面值都有一個十進制值17:
let decimalInteger = 17
let binaryInteger = 0b10001 // 17 二進制
let octalInteger = 0o21 // 17 八進制
let hexadecimalInteger = 0x11 // 17 十六進制
複製代碼
浮點字面值能夠是十進制(沒有前綴)或十六進制(有0x前綴)。它們必須在小數點的兩邊都有一個數字(或十六進制數)。十進制浮點數還能夠有一個可選的指數,由大寫或小寫e表示;十六進制浮點數必須有一個指數,用大寫或小寫p表示。
對於指數爲exp的小數,底數乘以10exp:
對於指數爲exp的十六進制數,底數乘以2exp:
全部這些浮點文字的十進制值都是12.1875:
let decimalDouble = 12.1875
let exponentDouble = 1.21875e1
let hexadecimalDouble = 0xC.3p0
複製代碼
數值文字能夠包含額外的格式,以使它們更容易閱讀。整數和浮點數均可以用額外的零來填充,而且能夠包含下劃線來加強可讀性。兩種格式都不會影響文字的基本值:
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1
複製代碼
對代碼中的全部通用整型常量和變量使用Int類型,即便已知它們是非負的。在平常狀況中使用默認整數類型意味着整型常量和變量在代碼中當即能夠互操做,並將匹配整型文字值的推斷類型。
只有在手頭的任務特別須要其餘整數類型時才使用它們,由於外部源顯式地調整了數據大小,或者爲了性能、內存使用或其餘必要的優化。在這些狀況下使用顯式大小的類型有助於捕獲任何意外值溢出,並隱式記錄所使用數據的性質。
能夠存儲在整型常量或變量中的數字的範圍對於每種數值類型是不一樣的。Int8常量或變量能夠存儲-128到127之間的數字,而UInt8常量或變量能夠存儲0到255之間的數字。當你的代碼編譯時,一個不適合大小整數類型的常量或變量的數字被報告爲一個錯誤:
let cannotBeNegative: UInt8 = -1
// UInt8 cannot store negative numbers, and so this will report an error
let tooBig: Int8 = Int8.max + 1
// Int8 cannot store a number larger than its maximum value,
// and so this will also report an error
複製代碼
因爲每一個數值類型能夠存儲不一樣範圍的值,所以必須根據具體狀況選擇進行數值類型轉換。這種可選擇的方法能夠防止隱藏的轉換錯誤,並有助於在代碼中顯式地顯示類型轉換意圖。
要將一種特定的數字類型轉換爲另外一種,可使用現有值初始化所需類型的新數字。在下面的示例中,常數2000的類型爲UInt16,而常數1的類型爲UInt8。它們不能直接相加,由於它們不是同一類型。相反,這個例子調用UInt16(one)來建立一個新的初始化值爲one的UInt16,並使用這個值代替原來的值:
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)
複製代碼
由於添加的兩邊如今都是UInt16類型,因此容許添加。輸出常數(twoThousandAndOne)被推斷爲UInt16類型,由於它是兩個UInt16值的和。
SomeType(ofInitialValue)是調用Swift類型的初始化器並傳入初始值的默認方法。在後臺,UInt16有一個接受UInt8值的初始化器,所以這個初始化器用於從現有的UInt8生成一個新的UInt16。可是,您不能在這裏傳入任何類型—它必須是UInt16提供初始化器的類型。擴展包括擴展示有類型以提供接受新類型(包括您本身的類型定義)的初始化器。
整數和浮點數類型之間的轉換必須明確:
let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine
// pi equals 3.14159, and is inferred to be of type Double
複製代碼
在這裏,常量3的值用於建立一個類型爲Double的新值,這樣加法的兩邊都是相同的類型。若是不進行此轉換,則不容許添加。
浮點到整數的轉換也必須明確。整數類型能夠用雙值或浮點值初始化:
let integerPi = Int(pi)
// integerPi equals 3, and is inferred to be of type Int
複製代碼
以這種方式初始化新的整數值時,浮點值老是被截斷。這意味着4.75變成4,而-3.9變成-3。
注意 組合數值常量和變量的規則與組合數值文字的規則不一樣。文字值3能夠直接添加到文字值0.14159,由於數字文字自己沒有顯式的in和of類型。它們的類型只有在由編譯器計算時纔會推斷出來。
類型別名定義現有類型的替代名稱。能夠經過typealias關鍵詞定義類型別名。
當你想經過上下文更合適的名稱來引用一個現有的類型時,類型別名頗有用,例如當從外部來源處理特定大小的數據時:
typealias AudioSample = UInt16
複製代碼
一旦定義類型別名,你能夠在任何地方使用別名,在可能使用原始的名稱的地方:
var maxAmplitudeFound = AudioSample.min
// maxAmplitudeFound is now 0
複製代碼
這裏,AudioSample被定義爲UInt16的別名。由於它是一個別名,調用AudioSample.min也就是調用UInt16.min,做爲maxAmplitudeFound爲0的值。
Swift有一個基本的布爾類型,叫作Bool。布爾值被稱爲邏輯值,由於它們只能是真或假。Swift提供了兩個布爾常量值true和false:
let orangesAreOrange = true
let turnipsAreDelicious = false
複製代碼
orangesAreOrange和turnipsAreDelicious的類型已經被推斷爲Bool,由於它們是用布爾文字值初始化的。與上面的Int和Double同樣,若是在建立常量或變量時就將它們設置爲true或false,則不須要將它們聲明爲Bool。當Swift用其餘已知類型的值初始化常量或變量時,類型推斷有助於使Swift代碼更加簡潔和可讀。
布爾值在處理條件語句時特別有用,好比if語句:
if turnipsAreDelicious {
print("Mmm, tasty turnips!")
} else {
print("Eww, turnips are horrible.")
}
// Prints "Eww, turnips are horrible."
複製代碼
條件語句(如if語句)在控制流 中有更詳細的介紹。
Swift的類型安全防止非布爾值被Bool替換。下面的示例報告了編譯時錯誤:
let i = 1
if i {
// this example will not compile, and will report an error
}
複製代碼
可是,下面的另外一個例子是有效的:
let i = 1
if i == 1 {
// this example will compile successfully
}
複製代碼
i == 1比較的結果是Bool類型,所以第二個示例經過了類型檢查。像i == 1這樣的比較在基本運算符中討論。
與Swift中的其餘類型安全示例同樣,這種方法避免了意外錯誤,並確保特定代碼段的意圖始終清晰。
元組將多個值分組爲一個複合值。元組中的值能夠是任何類型,沒必要彼此具備相同的類型。
在本例中,(404,「Not Found」)是描述HTTP狀態代碼的元組。HTTP狀態碼是web服務器在請求web頁面時返回的特殊值。若是你請求的網頁不存在,它會返回404 Not Found狀態碼。
let http404Error = (404, "Not Found")
// http404Error is of type (Int, String), and equals (404, "Not Found")
複製代碼
元組將一個Int和一個字符串組合在一塊兒,爲HTTP狀態碼提供兩個單獨的值:一個數字和一個可讀的描述。它能夠被描述爲「類型(Int, String)的元組」。
您能夠根據類型的任意排列建立元組,它們能夠包含任意多的不一樣類型。沒有什麼能夠阻止您擁有類型(Int, Int, Int)或(String, Bool)的元組,或者您須要的任何其餘置換。
您能夠將元組的內容分解爲單獨的常量或變量,而後像往常同樣訪問它們:
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
// Prints "The status code is 404"
print("The status message is \(statusMessage)")
// Prints "The status message is Not Found"
複製代碼
若是你只須要一些元組的值,當你分解元組的時候,用一個下劃線(_)忽略部分元組:
let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// Prints "The status code is 404"
複製代碼
或者,使用從0開始的索引號訪問元組中的單個元素值:
print("The status code is \(http404Error.0)")
// Prints "The status code is 404"
print("The status message is \(http404Error.1)")
// Prints "The status message is Not Found"
複製代碼
當元組被定義時,您能夠命名元組中的單個元素:
let http200Status = (statusCode: 200, description: "OK")
複製代碼
若是你在一個元組中命名元素,你可使用元素名來訪問這些元素的值:
print("The status code is \(http200Status.statusCode)")
// Prints "The status code is 200"
print("The status message is \(http200Status.description)")
// Prints "The status message is OK"
複製代碼
元組做爲函數的返回值特別有用。試圖檢索web頁面的函數可能會返回(Int, String)元組類型,以描述頁面檢索的成功或失敗。經過返回具備兩個不一樣類型值的元組,與只能返回單個類型的單個值相比,函數提供了關於其結果的更有用的信息。有關更多信息,請參見具備多個返回值的函數。
注意 元組對於相關值的簡單組很是有用。它們不適合建立複雜的數據結構。若是數據結構可能更復雜,那麼將其建模爲類或結構體,而不是元組。有關更多信息,請參見結構體和類。
在可能沒有值的狀況下使用可選值。可選的表示兩種可能:要麼有一個值,您能夠展開可選的來訪問該值,要麼根本沒有值。
注意 可選值的概念在C或Objective-C中不存在。Objective-C中最接近的是,從方法中返回nil的能力,不然會返回一個對象,nil表示「缺乏一個有效對象」。可是,這隻適用於對象,而不適用於結構體、基本C類型或枚舉值。對於這些類型,Objective-C方法一般返回一個特殊的值(好比NSNotFound)來表示沒有值。這種假設方法的調用者知道有一個特殊的值要進行測試,而且記得檢查它。Swift的可選值可讓你指示任何類型的值是否存在,而不須要特殊的常量。
下面是一個示例,說明如何使用可選值來處理缺乏值的狀況。Swift的Int類型有一個初始化器,它試圖將字符串值轉換爲Int值。可是,不是每一個字符串均可以轉換爲整數。字符串「123」能夠轉換爲數字值123,可是字符串「hello, world」沒有明顯的數字值能夠轉換。
下面的例子使用了初始化器來嘗試將一個字符串轉換成Int類型:
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber is inferred to be of type "Int?", or "optional Int"
複製代碼
由於初始化器可能失敗,它返回一個可選的整型,而不是整型。問號表示它包含的值是可選的,這意味着它可能包含一些Int值,也可能根本不包含值。它不能包含任何其餘東西,好比Bool值或String值。要麼是整數,要麼什麼都不是)
經過分配特殊值nil,設置一個可選的變量爲無值狀態:
var serverResponseCode: Int? = 404
// serverResponseCode contains an actual Int value of 404
serverResponseCode = nil
// serverResponseCode now contains no value
複製代碼
注意 不能對非可選常量和變量使用nil。若是代碼中的常量或變量在某些條件下須要處理缺乏值的狀況,請始終將其聲明爲適當類型的可選值。
若是定義了一個可選變量,而且沒有給它設值,那麼它的值默認是nil:
var surveyAnswer: String?
// surveyAnswer is automatically set to nil
複製代碼
注意 Swift裏的nil和OC裏的不一樣,OC裏的nil是一個指針,指向一個不存在的對象。Swift裏的nil不是一個指針--它是某種類型的值的缺失。任何類型的選項均可以設置爲nil,而不只僅是對象類型。
經過比較可選值和空值,可使用if語句來肯定可選值是否包含值。您可使用「等於」操做符(==)或「不等於」操做符(!=)執行比較。
若是可選值有值,會被認爲不是nil:
if convertedNumber != nil {
print("convertedNumber contains some integer value.")
}
// Prints "convertedNumber contains some integer value."
複製代碼
一旦肯定可選值有值,能夠經過在可選名稱的末尾添加感嘆號(!)來訪問其基礎值。感嘆號有效地表示:「我知道這個可選值確定有一個值;請使用它。這被稱爲可選值的強制解包:
if convertedNumber != nil {
print("convertedNumber has an integer value of \(convertedNumber!).")
}
// Prints "convertedNumber has an integer value of 123."
複製代碼
想要了解更多If語句,請參閱控制流。
注意 試着使用!訪問不存在的可選值將觸發運行時錯誤。在使用前,必定要確保一個可選的包含一個非nil值!強制打開它的值。
您可使用可選綁定來查明可選項是否包含值,若是包含值,則使該值做爲臨時常量或變量可用。可選綁定能夠與if和while語句一塊兒使用,以檢查可選語句中的值,並將該值提取爲常量或變量,這是單個操做的一部分。if和while語句在控制流中有更詳細的描述。
使用If語句寫一個以下的可選綁定:
if let constantName = someOptional {
statements
}
複製代碼
您能夠重寫Optionals部分中的possibleNumber示例,以使用可選綁定而不是強制解包:
if let actualNumber = Int(possibleNumber) {
print("The string \"\(possibleNumber)\" has an integer value of \(actualNumber)")
} else {
print("The string \"\(possibleNumber)\" could not be converted to an integer")
}
// Prints "The string "123" has an integer value of 123"
複製代碼
這段代碼的意思是: 「若是Int(possibleNumber)返回的可選整數包含一個值,則設置一個名爲actualNumber的新常量爲可選整數中包含的值。」
若是轉換成功,就能夠在If語句的第一個分支中使用actualNumber常數。它已經用可選項中包含的值進行了初始化,所以不須要使用!後綴來訪問其值。在本例中,actualNumber只是用於打印轉換的結果。
可使用可選綁定的常量和變量。若是您想在If語句的第一個分支中操做actualNumber的值,則能夠編寫If var actualNumber,而可選語句中包含的值將做爲變量而不是常量可用。
您能夠在一個if語句中包含任意多的可選綁定和布爾條件,用逗號分隔。若是可選綁定中的任何值爲nil或任何布爾值條件爲false,則整個If語句的條件被認爲爲false。下面的if語句是等價的:
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
// Prints "4 < 42 < 100"
if let firstNumber = Int("4") {
if let secondNumber = Int("42") {
if firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
}
}
// Prints "4 < 42 < 100"
複製代碼
注意 在if語句中使用可選綁定建立的常量和變量只能在if語句體中使用。相反,使用guard語句建立的常量和變量能夠在guard語句後面的代碼行中使用,如Early Exit中所述。
如上所述,可選值表示常量或變量容許「無值」。可選值能夠用if語句檢查值是否存在,也能夠用可選綁定有條件地解除包裝,以訪問可選值(若是存在)。
有時候從程序結構上,可選值在第一次設置後,總會有一個值。在這些狀況下,在訪問可選值的時候,移除檢查和解包的操做是有效的,由於它老是安全地假定有一個值。
這些類型的可選值被定義爲隱式的解包可選值。經過在但願使類型可選的後面放置感嘆號(String!)而不是問號(String?)來編寫可選的隱式解包。在使用可選名稱時,不要在其後放置感嘆號,而應在聲明可選類型時在其後放置感嘆號。
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // requires an exclamation point
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // no need for an exclamation point
複製代碼
(注:這裏終於清楚地明白了?和!的用法,說明學一門語言仍是要從官方文檔開始)
你能夠將可選的隱式解包看做容許可選的對象在須要時強制解包。當你使用隱式解包裝可選值時,Swift首先嚐試將其做爲普通可選值使用;若是不能做爲可選值使用,Swift強制打開該值。在上面的代碼中,可選值assumedString在將其值分配給implicitString以前被強制解除包裝,由於implicitString具備顯式的、非可選的字符串類型。在下面的代碼中,optionalString沒有顯式類型,因此它是一個普通的可選類型。
let optionalString = assumedString
// The type of optionalString is "String?" and assumedString isn't force-unwrapped. 複製代碼
若是一個可選的隱式解包是nil,而且您嘗試訪問它的包裝值,您將觸發一個運行時錯誤。其結果與在不包含值的普通可選項後放置感嘆號徹底相同。
你能夠檢查一個可選的隱式解包是否爲nil,就像你檢查一個普通的可選:
if assumedString != nil {
print(assumedString!)
}
// Prints "An implicitly unwrapped optional string."
複製代碼
你也可使用可選值綁定隱式解包可選的值,在一個單獨的語句中檢查和解包它的值:
if let definiteString = assumedString {
print(definiteString)
}
// Prints "An implicitly unwrapped optional string."
複製代碼
注意 當一個變量可能在之後變成nil時,不要使用可選值綁定隱式解包可選的值。若是須要在變量的生命週期內檢查nil值,請始終使用普通的可選類型。
使用錯誤處理來響應程序在執行過程當中可能遇到的錯誤條件。
可選值可使用值的存在或不存在來傳遞函數的成功或失敗,與之相反,錯誤處理容許您肯定失敗的根本緣由,並在必要時將錯誤傳播到程序的另外一部分。
當函數遇到錯誤條件時,它會拋出錯誤。而後,函數的調用者能夠捕獲錯誤並做出適當的響應。
func canThrowAnError() throws {
// this function may or may not throw an error
}
複製代碼
函數經過在其聲明中包含throws關鍵字來表示能夠拋出錯誤。當調用可能拋出錯誤的函數時,應在表達式前添加try關鍵字。
Swift自動將錯誤傳播到當前範圍以外,直到它們被catch子句處理。
do {
try canThrowAnError()
// no error was thrown
} catch {
// an error was thrown
}
複製代碼
do語句建立一個新的包含範圍,容許將錯誤傳播到一個或多個catch子句。
下面是一個例子,說明如何使用錯誤處理來響應不一樣的錯誤條件:
func makeASandwich() throws {
// ...
}
do {
try makeASandwich()
eatASandwich()
} catch SandwichError.outOfCleanDishes {
washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
buyGroceries(ingredients)
}
複製代碼
在本例中,若是沒有乾淨的盤子或缺乏任何配料,makeASandwich()函數將拋出一個錯誤。由於makeASandwich()可能拋出錯誤,因此函數調用被包裝在一個try表達式中。經過將函數調用包裝在do語句中,拋出的任何錯誤都將傳播到提供的catch子句。
若是沒有拋出錯誤,則調用eatASandwich()函數。若是拋出一個錯誤,而且它與sandwichError匹配。在outOfCleanDishes狀況下,則調用washDishes()函數。若是拋出一個錯誤,而且它與sandwichError匹配。missingcomponents狀況下,使用catch模式捕獲的相關[String]值調用buyGroceries(_:)函數。
錯誤處理中更詳細地介紹了拋出、捕獲和傳播錯誤。
斷言和前置條件是在運行時進行的檢查。在執行任何其餘代碼以前,使用它們確保知足必要條件。若是斷言或先決條件中的布爾值爲真,則代碼執行照常繼續。若是條件計算爲false,則程序的當前狀態無效;代碼執行結束,應用程序終止。
在編碼時,可使用斷言和先決條件來表示所做的假設和指望,所以能夠將它們做爲代碼的一部分。斷言幫助您在開發期間發現錯誤和不正確的假設,而前提條件幫助您檢測生產中的問題。
除了在運行時驗證您的指望以外,斷言和先決條件也成爲代碼中有用的文檔形式。與上面錯誤處理中討論的錯誤條件不一樣,斷言和前置條件不會用於可恢復的或預期的錯誤。因爲失敗的斷言或先決條件指示無效的程序狀態,所以沒法捕獲失敗的斷言。
使用斷言和先決條件不能替代以不太可能出現無效條件的方式設計代碼。可是,使用它們強制執行有效的數據和狀態會致使應用程序在出現無效狀態時可預測地終止,並有助於使問題更容易調試。在檢測到無效狀態時當即中止執行還有助於限制由該無效狀態形成的損害。
斷言和前提條件的區別在於它們被檢查的時候:斷言只在調試構建中被檢查,可是前提條件在調試和生產構建中都被檢查。在生產構建中,不計算斷言中的條件。這意味着您能夠在開發過程當中使用任意數量的斷言,而不會影響生產中的性能。
經過從Swift標準庫中調用assert(::file:line:)函數來編寫斷言。向該函數傳遞一個計算結果爲true或false的表達式,以及一條消息,若是條件的結果爲false,則顯示該消息。例如:
let age = -3
assert(age >= 0, "A person's age can't be less than zero.")
// This assertion fails because -3 is not >= 0.
複製代碼
在本例中,若是age >= 0的值爲真(即age的值非負),則繼續執行代碼。若是age的值是負數,如上面的代碼所示,那麼age >= 0計算爲false,斷言失敗,終止應用程序。
您能夠省略斷言消息—例如,當它只是以散文形式重複條件時。
assert(age >= 0)
複製代碼
若是代碼已經檢查了條件,那麼可使用assertionFailure(_:file:line:)函數來表示斷言失敗了。例如:
if age > 10 {
print("You can ride the roller-coaster or the ferris wheel.")
} else if age >= 0 {
print("You can ride the ferris wheel.")
} else {
assertionFailure("A person's age can't be less than zero.")
}
複製代碼
只要條件可能爲假,但必須爲真,代碼才能繼續執行,就使用前置條件。例如,使用先決條件檢查下標是否超出範圍,或檢查函數是否傳遞了有效值。
你能夠經過調用 precondition(_:_:file:line:)
函數來編寫一個先決條件。向該函數傳遞一個計算結果爲true或false的表達式,以及一條消息,若是條件的結果爲false,則顯示該消息。例如:
// In the implementation of a subscript...
precondition(index > 0, "Index must be greater than zero.")
複製代碼
您還能夠調用preconditionFailure(_:file:line:)函數來指示發生了故障——例如,若是採用了switch的默認狀況,可是全部有效的輸入數據應該由switch的其餘狀況之一處理。
注意 若是以unchecked模式(-Ounchecked)編譯,則不會檢查前置條件。編譯器假設前提條件老是爲真,並相應地優化代碼。然而,不管優化設置如何,fatalError(_:file:line:)函數老是會中止執行。
您能夠在原型和早期開發期間使用fatalError(_:file:line:)函數爲還沒有實現的功能建立存根,方法是編寫fatalError(「未實現」)做爲存根實現。由於與斷言或先決條件不一樣,致命錯誤歷來沒有被優化出來,因此能夠確定,若是遇到存根實現,執行老是會中止。
經過這一章節的學習,能夠了解Swift基礎的一些知識以及它特有的一些功能:
參考文檔:Swift - The Basics