Swift 是一門開發(fā) iOS, macOS, watchOS 和 tvOS 應(yīng)用的新語言。然而,如果你有 C 或者 Objective-C 開發(fā)經(jīng)驗(yàn)的話,你會發(fā)現(xiàn) Swift 的很多內(nèi)容都是你熟悉的。
swift swift2
Swift 包含了 C 和 Objective-C 上所有基礎(chǔ)數(shù)據(jù)類型,Int 表示整型值;Double和 Float表示浮點(diǎn)型值;Bool是布爾型值;String是文本型數(shù)據(jù)。 Swift 還提供了三個基本的集合類型,Array,Set和Dictionary
就像 C 語言一樣,Swift 使用變量來進(jìn)行存儲并通過變量名來關(guān)聯(lián)值。在 Swift 中,廣泛的使用著值不可變的變量,它們就是常量,而且比 C 語言的常量更強(qiáng)大。在 Swift 中,如果你要處理的值不需要改變,那使用常量可以讓你的代碼更加安全并且更清晰地表達(dá)你的意圖。
除了我們熟悉的類型,Swift 還增加了 Objective-C 中沒有的高階數(shù)據(jù)類型比如元組(Tuple)。元組可以讓你創(chuàng)建或者傳遞一組數(shù)據(jù),比如作為函數(shù)的返回值時,你可以用一個元組可以返回多個值
Swift 還增加了可選(Optional)類型,用于處理值缺失的情況??蛇x表示 “那兒有一個值,并且它等于 x ” 或者 “那兒沒有值” ??蛇x有點(diǎn)像在 Objective-C 中使用 nil ,但是它可以用在任何類型上,不僅僅是類。可選類型比 Objective-C 中的 nil 指針更加安全也更具表現(xiàn)力,它是 Swift 許多強(qiáng)大特性的重要組成部分。
Swift 是一門類型安全的語言,這意味著 Swift 可以讓你清楚地知道值的類型。如果你的代碼需要一個 String ,類型安全會阻止你不小心傳入一個 Int 。同樣的,如果你的代碼需要一個 String,類型安全會阻止你意外傳入一個可選的 String 。類型安全可以幫助你在開發(fā)階段盡早發(fā)現(xiàn)并修正錯誤
常量和變量
常量和變量把一個名字和制定類型的指聯(lián)系起來,比如把"name" 和 "Edison"聯(lián)系起來
聲明常量和變量
let聲明常量,var聲明變量
var helleStr : NSString = "hello"
var i = 0, b=9, c = "nihao"
注意:如果你的代碼中有不需要改變的值,
請用let把它聲明成常量
類型標(biāo)注
當(dāng)你聲明常量或者變量的可以添加直接直接添加類型
比如
var nameStr : NSString
var helleStr : NSString = "hello"
這樣就給常量或者變量聲明的屬性,表示這個變量儲存的是制定類型的值
一般來說我們很少需要寫類型標(biāo)注,如果你聲明常量或者變量的時候初始化一個值,swift可以推斷出這個常量或者變量的類型
常量和變量的命名
swift允許你有你任何你喜歡的字符座位常量和變量名,包括unicode編碼
let ??二 = "dog"
let 天涯 = "tianya"
常量與變量名不能包含數(shù)學(xué)符號,箭頭,保留的(或者非法的)Unicode 碼位,連線與制表符。也不能以數(shù)字開頭,但是可以在常量與變量名的其他地方包含數(shù)字
一旦你將常量或者變量聲明為確定的類型,你就不能使用相同的名字再次進(jìn)行聲明,或者改變其存儲的值的類型。同時,你也不能將常量與變量進(jìn)行互轉(zhuǎn)
輸出常量和變量
print(helleStr)
print("hellstr:\(helleStr) tianya:\(天涯)")
分號
與大部分編程不同,swift并不強(qiáng)制要求在每句代碼后都得加上分號,但是有一種情況下,是必須要加的,就是在同一行寫多句獨(dú)立的代碼
var intA = 3 ; print(intA)
整數(shù)
整數(shù)就是沒有小數(shù)部分的數(shù)字,比如 42 和 -23 。整數(shù)可以是 有符號(正、負(fù)、零)或者 無符號(正、零)。
Swift 提供了8,16,32和64位的有符號和無符號整數(shù)類型。這些整數(shù)類型和 C 語言的命名方式很像,比如8位無符號整數(shù)類型是UInt8,32位有符號整數(shù)類型是 Int32 。就像 Swift 的其他類型一樣,整數(shù)類型采用大寫命名法
Int
一般來說,你不需要專門指定證書的長度,swift提供了一個特殊的整數(shù)類型Int,長度與當(dāng)前平臺的原生長度一樣
- 在32位平臺上,
Int與Int32長度一樣 - 在64位平臺上,
Int與Int64長度一樣
除非你需要特定長度的整數(shù),一般來說使用 Int 就夠了。這可以提高代碼一致性和可復(fù)用性。即使是在32位平臺上,Int 可以存儲的整數(shù)范圍也可以達(dá)到 -2,147,483,648 ~ 2,147,483,647 ,大多數(shù)時候這已經(jīng)足夠大了
UInt
Swift 也提供了一個特殊的無符號類型 UInt,長度與當(dāng)前平臺的原生字長相同
浮點(diǎn)數(shù)
浮點(diǎn)數(shù)是有小數(shù)部分的數(shù)字,比如3.14159,0.2,-7.456
浮點(diǎn)數(shù)比整數(shù)表示的范圍更大,可以儲存比Int更大或者更小的數(shù)字,swift也提供了兩種浮點(diǎn)數(shù)
- Double
表示64位浮點(diǎn)數(shù),當(dāng)你需要存儲很大或者很高精度的浮點(diǎn)數(shù)時請使用此類型 - Float
表示32位浮點(diǎn)數(shù)。精度要求不高的話可以使用此類型
Double精確度很高,至少有15位數(shù)字,而Float只有6位數(shù)字。選擇哪個類型取決于你的代碼需要處理的值的范圍,在兩種類型都匹配的情況下,將優(yōu)先選擇 Double
類型安全和類型推斷
Swift 是一個類型安全(type safe)的語言。類型安全的語言可以讓你清楚地知道代碼要處理的值的類型。如果你的代碼需要一個String,你絕對不可能不小心傳進(jìn)去一個Int
由于 Swift 是類型安全的,所以它會在編譯你的代碼時進(jìn)行類型檢查(type checks),并把不匹配的類型標(biāo)記為錯誤。這可以讓你在開發(fā)的時候盡早發(fā)現(xiàn)并修復(fù)錯誤
當(dāng)你要處理不同類型的值時,類型檢查可以幫你避免錯誤。然而,這并不是說你每次聲明常量和變量的時候都需要顯式指定類型。如果你沒有顯式指定類型,Swift 會使用類型推斷(type inference)來選擇合適的類型。有了類型推斷,編譯器可以在編譯代碼的時候自動推斷出表達(dá)式的類型。原理很簡單,只要檢查你賦的值即可
因?yàn)橛蓄愋屯茢啵?C 或者 Objective-C 比起來 Swift 很少需要聲明類型。常量和變量雖然需要明確類型,但是大部分工作并不需要你自己來完成
當(dāng)你聲明常量或者變量并賦初值的時候類型推斷非常有用。當(dāng)你在聲明常量或者變量的時候賦給它們一個字面量(literal value 或 literal)即可觸發(fā)類型推斷。(字面量就是會直接出現(xiàn)在你代碼中的值,比如 42 和 3.14159 。)
例如,如果你給一個新常量賦值 10 并且沒有標(biāo)明類型,Swift 可以推斷出常量類型是 Int ,因?yàn)槟憬o它賦的初始值看起來像一個整數(shù)
let intValue = 10
同理,如果你沒有給浮點(diǎn)字面量標(biāo)明類型,Swift 會推斷你想要的是 Double
let douValue = 4.675
當(dāng)推斷浮點(diǎn)數(shù)的類型時,Swift 總是會選擇 Double 而不是Float
如果表達(dá)式中同時出現(xiàn)了整數(shù)和浮點(diǎn)數(shù),會被推斷為 Double 類型:
let value = 10+7.78
數(shù)值型字面量
整數(shù)字面量可以被寫作
- 一個十進(jìn)制數(shù),沒有前綴
- 一個二進(jìn)制數(shù),前綴是
0b - 一個八進(jìn)制數(shù),前綴是
0o - 一個十六進(jìn)制數(shù),前綴是
0x
浮點(diǎn)字面量可以是十進(jìn)制(沒有前綴)或者是十六進(jìn)制(前綴是 0x ),小數(shù)點(diǎn)兩邊必須有至少一個十進(jìn)制數(shù)字(或者是十六進(jìn)制的數(shù)字)。十進(jìn)制浮點(diǎn)數(shù)也可以有一個可選的指數(shù)(exponent),通過大寫或者小寫的 e 來指定;十六進(jìn)制浮點(diǎn)數(shù)必須有一個指數(shù),通過大寫或者小寫的 p 來指定
如果一個十進(jìn)制數(shù)的指數(shù)為 exp,那這個數(shù)相當(dāng)于基數(shù)和10^exp的乘積
-
1.25e2表示1.25 × 10^2,等于125.0。
-1.25e-2表示1.25 × 10^-2,等于0.0125
如果一個十六進(jìn)制數(shù)的指數(shù)為exp,那這個數(shù)相當(dāng)于基數(shù)和2^exp的乘積
-
0xFp2表示15 × 2^2,等于60.0 -
0xFp-2表示15 × 2^-2,等于3.75
數(shù)值型類型轉(zhuǎn)換
通常來講,即使代碼中的整數(shù)常量和變量已知非負(fù),也請使用Int類型??偸鞘褂媚J(rèn)的整數(shù)類型可以保證你的整數(shù)常量和變量可以直接被復(fù)用并且可以匹配整數(shù)類字面量的類型推斷
只有在必要的時候才使用其他整數(shù)類型,比如要處理外部的長度明確的數(shù)據(jù)或者為了優(yōu)化性能、內(nèi)存占用等等。使用顯式指定長度的類型可以及時發(fā)現(xiàn)值溢出并且可以暗示正在處理特殊數(shù)據(jù)
整數(shù)轉(zhuǎn)換
不同整數(shù)類型的變量和常量可以存儲不同范圍的數(shù)字。Int8類型的常量或者變量可以存儲的數(shù)字范圍是-128~127,而UInt8類型的常量或者變量能存儲的數(shù)字范圍是0~255。如果數(shù)字超出了常量或者變量可存儲的范圍,編譯的時候會報(bào)錯

由于每種整數(shù)類型都可以存儲不同范圍的值,所以你必須根據(jù)不同情況選擇性使用數(shù)值型類型轉(zhuǎn)換。這種選擇性使用的方式,可以預(yù)防隱式轉(zhuǎn)換的錯誤并讓你的代碼中的類型轉(zhuǎn)換意圖變得清晰
要將一種數(shù)字類型轉(zhuǎn)換成另一種,你要用當(dāng)前值來初始化一個期望類型的新數(shù)字,這個數(shù)字的類型就是你的目標(biāo)類型。在下面的例子中,常量twoThousand是UInt16類型,然而常量one是UInt8類型。它們不能直接相加,因?yàn)樗鼈冾愋筒煌?。所以要調(diào)用UInt16(one)來創(chuàng)建一個新的UInt16數(shù)字并用one的值來初始化,然后使用這個新數(shù)字來計(jì)算
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)
整數(shù)和浮點(diǎn)數(shù)轉(zhuǎn)換
整數(shù)和浮點(diǎn)數(shù)的轉(zhuǎn)換必須顯式指定類型:
let intC = 33
let floatB = 4.67
let doubleC = Double(intC) + floatB
類型別名
類型別名(type aliases)就是給現(xiàn)有類型定義另一個名字。你可以使用typealias關(guān)鍵字來定義類型別名
當(dāng)你想要給現(xiàn)有類型起一個更有意義的名字時,類型別名非常有用。假設(shè)你正在處理特定長度的外部資源的數(shù)據(jù):
typealias AudioSample = UInt16
定義了一個類型別名之后,你可以在任何使用原始名的地方使用別名:
var maxAmplitudeFound = AudioSample.min
// maxAmplitudeFound 現(xiàn)在是 0
本例中,AudioSample被定義為UInt16的一個別名。因?yàn)樗莿e名,AudioSample.min實(shí)際上是UInt16.min,所以會給maxAmplitudeFound賦一個初值0。
布爾值
Swift 有一個基本的布爾(Boolean)類型,叫做Bool。布爾值指邏輯上的值,因?yàn)樗鼈冎荒苁钦婊蛘呒佟wift 有兩個布爾常量,true 和 false:
let boolA = true
let boolB = false
boolA 和 boolB 的類型會被推斷為 Bool,因?yàn)樗鼈兊某踔凳遣紶栕置媪俊>拖裰疤岬降?Int 和 Double 一樣,如果你創(chuàng)建變量的時候給它們賦值 true 或者 false,那你不需要將常量或者變量聲明為 Bool 類型。初始化常量或者變量的時候如果所賦的值類型已知,就可以觸發(fā)類型推斷,這讓 Swift 代碼更加簡潔并且可讀性更高
當(dāng)你編寫條件語句比如if語句,布爾值就很有作用
if boolA {
print("YES")
}else{
print("NO")
}
元組
元組(tuples) 把多個值組合成一個復(fù)合值。元組內(nèi)的值可以是任意類型,并不要求是相同類型
你可以把任意順序的類型組合成一個元組,這個元組可以包含所有類型。只要你想,你可以創(chuàng)建一個類型為 (Int, Int, Int) 或者 (String, Bool) 或者其他任何你想要的組合的元組。
你可以將一個元組的內(nèi)容分解(decompose)成單獨(dú)的常量和變量,然后你就可以正常使用它們了:
let (name,age,height) = ("Edison",13,177)
print(name,age,height)
還可以只通過下標(biāo)來訪問元組的單個元素
let faceId = ("good",144)
let (face,weight) = faceId
print("\(faceId.0) -- \(faceId.1)")
你可以在定義元組的時候給單個元素命名
let tupleName = (eName:"edison",eAge:14)
print("enmae=\(tupleName.eName) age=\(tupleName.eAge)")
作為函數(shù)返回值時,元組非常有用。一個用來獲取網(wǎng)頁的函數(shù)可能會返回一個 (Int, String) 元組來描述是否獲取成功。和只能返回一個類型的值比較起來,一個包含兩個不同類型值的元組可以讓函數(shù)的返回信息更有用
可選類型
使用可選類型(optionals)來處理可能確實(shí)的情況,可選類型表示:
- 有值,等于x
- 沒有值
注意
c和oc中并沒有可選類型這個概念,最接近這個概念,是oc中的一個特性(一個方法要么返回對象,要么返回nil,nil表示確實(shí)一個合法對象,但這只對oc對象有作用,對c,結(jié)構(gòu)體都不能用,對于這些類型,Objective-C 方法一般會返回一個特殊值(比如NSNotFound)來暗示值缺失。這種方法假設(shè)方法的調(diào)用者知道并記得對特殊值進(jìn)行判斷),然而,Swift 的可選類型可以讓你暗示任意類型的值缺失,并不需要一個特殊值
let的可選項(xiàng)沒有初始化,var的可選項(xiàng)初始值為nil
來看一個例子。Swift 的 Int 類型有一種構(gòu)造器,作用是將一個 String 值轉(zhuǎn)換成一個 Int 值。然而,并不是所有的字符串都可以轉(zhuǎn)換成一個整數(shù)。字符串 "123" 可以被轉(zhuǎn)換成數(shù)字 123 ,但是字符串 "hello, world" 不行。
下面的例子使用這種構(gòu)造器來嘗試將一個 String 轉(zhuǎn)換成 Int:
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber 被推測為類型 "Int?", 或者類型 "optional Int"
因?yàn)樵摌?gòu)造器可能會失敗,所以它返回一個可選類型(optional)Int,而不是一個 Int。一個可選的 Int 被寫作 Int? 而不是 Int。問號暗示包含的值是可選類型,也就是說可能包含 Int 值也可能不包含值。(不能包含其他任何值比如 Bool 值或者 String 值。只能是 Int 或者什么都沒有。)
nil
你可以給可選變量賦值為nil來表示它沒有值:
var value: Int? = 404
// value 包含一個可選的 Int 值 404
value = nil
// value 現(xiàn)在不包含值
注意
nil不能用于非可選的常量和變量。如果你的代碼中有常量或者變量需要處理值缺失的情況,請把它們聲明成對應(yīng)的可選類型
如果你聲明一個可選常量或者變量但是沒有賦值,它們會自動被設(shè)置為 nil
注意
Swift 的 nil 和 Objective-C 中的 nil 并不一樣。在 Objective-C 中,nil 是一個指向不存在對象的指針。在 Swift 中,nil 不是指針——它是一個確定的值,用來表示值缺失。任何類型的可選狀態(tài)都可以被設(shè)置為 nil,不只是對象類型
if語句以及強(qiáng)制解析
你可以使用哥if語句和nil比較來判斷一個可選值是否包含值
你可以使用“相等”(==)或“不等”(!=)來執(zhí)行比較。
如果可選類型有值,它將不等于 nil:
var oStr = "oStr"
var a = Int(oStr)
if a != nil {
print("a有值")
}else{
print("a無值")
}
//結(jié)果是a無值
當(dāng)你確定可選類型確實(shí)包含值之后,你可以在可選的名字后面加一個感嘆號(!)來獲取值。這個驚嘆號表示“我知道這個可選有值,請使用它
var oStr = "123"
var a = Int(oStr)
if a != nil {
print("a有值\(a!)")
}else{
print("a無值")
}
但是如果用! 來強(qiáng)制解析不存在對可選值,就會出錯
var oStr = "oStr"
var a = Int(oStr)
print("a有值\(a!)")
// unexpectedly found nil while unwrapping an Optional value
這個奔潰就是強(qiáng)行解包一個nil值的變量
注意:
使用!來獲取一個不存在的可選值會導(dǎo)致運(yùn)行時錯誤。使用!來強(qiáng)制解析值之前,一定要確定可選包含一個非nil的值
可選綁定
使用可選綁定(optional binding)來判斷可選類型是否包含值,如果包含就把值賦給一個臨時常量或者變量
可選綁定可以用在 if 和 while 語句中,這條語句不僅可以用來判斷可選類型中是否有值,同時可以將可選類型中的值賦給一個常量或者變量
像下面這樣在 if 語句中寫一個可選綁定:
if let constantName = someOptional {
statements
}
你可以像上面這樣使用可選綁定來重寫 possibleNumber 這個
if let actualNumber = Int(possibleNumber) {
print("\'\(possibleNumber)\' has an integer value of \(actualNumber)")
} else {
print("\'\(possibleNumber)\' could not be converted to an integer")
}
這段代碼可以被理解為:
“如果 Int(possibleNumber) 返回的可選Int 包含一個值,創(chuàng)建一個叫做 actualNumber 的新常量并將可選包含的值賦給它?!?/p>
如果轉(zhuǎn)換成功,actualNumber常量可以在 if 語句的第一個分支中使用。它已經(jīng)被可選類型 包含的 值初始化過,所以不需要再使用 ! 后綴來獲取它的值。在這個例子中,actualNumber 只被用來輸出轉(zhuǎn)換結(jié)果。
你可以在可選綁定中使用常量和變量。如果你想在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")
}
// 輸出 "4 < 42 < 100"
if let firstNumber = Int("4") {
if let secondNumber = Int("42") {
if firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
}
}
// 輸出 "4 < 42 < 100"
注意: 在
if條件語句中使用常量和變量來創(chuàng)建一個可選綁定,僅在if語句的句中(body)中才能獲取到值
隱式解析可選類型
如上所述,可選類型暗示了常量或者變量可以“沒有值”。可選可以通過if 語句來判斷是否有值,如果有值的話可以通過可選綁定來解析值
有時候在程序架構(gòu)中,第一次被賦值之后,可以確定一個可選類型總會有值。在這種情況下,每次都要判斷和解析可選值是非常低效的,因?yàn)榭梢源_定它總會有值
這種類型的可選狀態(tài)被定義為隱式解析可選類型
把想要用作可選的類型的后面的問號(String?)改成感嘆號(String!)來聲明一個隱式解析可選類型
當(dāng)可選類型被第一次賦值之后就可以確定之后一直有值的時候,隱式解析可選類型非常有用。隱式解析可選類型主要被用在 Swift 中類的構(gòu)造過程中
一個隱式解析可選類型其實(shí)就是一個普通的可選類型,但是可以被當(dāng)做非可選類型來使用,并不需要每次都使用解析來獲取可選值。下面的例子展示了可選類型 String 和隱式解析可選類型 String 之間的區(qū)別:
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // 需要感嘆號來獲取值
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // 不需要感嘆號
你可以把隱式解析可選類型當(dāng)做一個可以自動解析的可選類型。你要做的只是聲明的時候把感嘆號放到類型的結(jié)尾,而不是每次取值的可選名字的結(jié)尾
如果你在隱式解析可選類型沒有值的時候嘗試取值,會觸發(fā)運(yùn)行時錯誤。和你在沒有值的普通可選類型后面加一個驚嘆號一樣
你仍然可以把隱式解析可選類型當(dāng)做普通可選類型來判斷它是否包含值:
if assumedString != nil {
print(assumedString)
}
// 輸出 "An implicitly unwrapped optional string."
你也可以在可選綁定中使用隱式解析可選類型來檢查并解析它的值:
if let definiteString = assumedString {
print(definiteString)
}
// 輸出 "An implicitly unwrapped optional string."
如果一個變量之后可能變成nil的話請不要使用隱式解析可選類型。如果你需要在變量的生命周期中判斷是否是nil的話,請使用普通可選類型。
使用斷言進(jìn)行調(diào)試
你可以使用swift標(biāo)準(zhǔn)庫assert(_:_:file:line:) ,函數(shù)來寫一個斷言。向這個函數(shù)傳入一個結(jié)果為 true 或者 false 的表達(dá)式以及一條信息,當(dāng)表達(dá)式的結(jié)果為 false 的時候這條信息會被顯示
let age = -3
assert(age >= 0, "A person's age cannot be less than zero")
// 因?yàn)?age < 0,所以斷言會觸發(fā)
在這個例子中,只有 age >= 0 為 true 時,即 age 的值非負(fù)的時候,代碼才會繼續(xù)執(zhí)行。如果 age 的值是負(fù)數(shù),就像代碼中那樣,age >= 0 為false,斷言被觸發(fā),終止應(yīng)用。