1.Swift 基礎(chǔ)類型
Swift
包含了 C
和 Objective-C
上所有基礎(chǔ)數(shù)據(jù)類型派撕,Int
表示整型值婉弹; Double
和 Float
表示浮點型值; Bool
是布爾型值终吼;String
是文本型數(shù)據(jù)镀赌。 Swift
還提供了三個基本的集合類型,Array
际跪,Set
和Dictionary
商佛。Swift
還增加了Objective-C
中沒有的高階數(shù)據(jù)類型比如元組(Tuple
)蛙粘。Swift
還增加了可選(Optional
)類型,用于處理值缺失的情況右莱】杷Γ可選類型比 Objective-C 中的 nil 指針更加安全也更具表現(xiàn)力。
2.常量和變量
常量和變量必須在使用前聲明,用let
來聲明常量但两,用var
來聲明變量。
let a = 10
var b = 11
var x = 0.0, y = 0.0, z = 0.0
當你聲明常量或者變量的時候可以加上類型標注
var str: String
給str
變量添加了類型標注
熟空,表示這個變量可以存儲 String
類型的值:
可以在一行中定義多個同樣類型的變量坟漱,用逗號分割,并在最后一個變量名之后添加類型標注:
var red, green, blue: Double
3.類型安全
和類型推斷
Swift
是一個類型安全(ype safe
)的語言.類型安全的語言可以讓你清楚地知道代碼要處理的值的類型慨代。 Swift
是類型安全的邢笙,所以它會在編譯
你的代碼時進行類型檢查
.由于類型推斷
,大部分工作時候聲明變量或常量的時候并不需要你自己來完成侍匙。
當推斷浮點數(shù)的類型時氮惯,Swift
總是會選擇Double
而不是Float
。
4.數(shù)值型字面量
一個十進制數(shù)想暗,沒有前綴
一個二進制數(shù)妇汗,前綴是0b
一個八進制數(shù),前綴是0o
oc或者c是 0
一個十六進制數(shù)说莫,前綴是0x
數(shù)值類字面量可以包括額外的格式來增強可讀性杨箭。整數(shù)和浮點數(shù)都可以添加額外的零并且包含下劃線,并不會影響字面量:
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1
整數(shù)轉(zhuǎn)換
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)
let integerPi = Int(pi)
當用這種方式來初始化一個新的整數(shù)值時储狭,浮點值會被截斷互婿。也就是說 3.895
會變成 3
,-10.9
會變成 -10
辽狈。
如果在需要使用Bool
類型的地方使用了非布爾值慈参,Swift
的類型安全機制會報錯。
let i = 1
if i {
// 這個例子不會通過編譯稻艰,會報錯
}
let i = 1
if i == 1 {
// 這個例子會編譯成功
}
*注意:Int
與Int8
的區(qū)別
5.元組
元組(tuples
)把多個值組合成一個復(fù)合值懂牧。元組內(nèi)的值可以是任意類型
,并不要求是相同類型尊勿。
let http404Error = (404, "Not Found")
// http404Error 的類型是 (Int, String)僧凤,值是 (404, "Not Found")
可以將一個元組的內(nèi)容分解(decompose)成單獨的常量和變量,然后你就可以正常使用它們
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
// 輸出 "The status code is 404"
print("The status message is \(statusMessage)")
// 輸出 "The status message is Not Found"
只需要一部分元組值元扔,分解的時候可以把要忽略的部分用下劃線(_)標記:
let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// 輸出 "The status code is 404"
可以通過下標來訪問元組中的單個元素躯保,下標從零開始:
print("The status code is \(http404Error.0)")
// 輸出 "The status code is 404"
print("The status message is \(http404Error.1)")
// 輸出 "The status message is Not Found"
鍵值
let http200Status = (statusCode: 200, description: "OK")
print("The status code is \(http200Status.statusCode)")
// 輸出 "The status code is 200"
print("The status message is \(http200Status.description)")
// 輸出 "The status message is OK"
*注意:元組在臨時組織值的時候很有用,但是并不適合創(chuàng)建復(fù)雜的數(shù)據(jù)結(jié)構(gòu)澎语。如果你的數(shù)據(jù)結(jié)構(gòu)并不是臨時使用途事,請使用類或者結(jié)構(gòu)體而不是元組验懊。
6.nil
C
和 Objective-C
中并沒有可選類型這個概念。最接近的是Objective-C
中的一個特性尸变,一個方法要不返回一個對象要不返回nil
义图,nil
表示“缺少一個合法的對象”。這只對對象起作用——對于結(jié)構(gòu)體召烂,基本的 C 類型
或者枚舉類型
不起作用碱工。對于這些類型,Objective-C
方法一般會返回一個特殊值(比如NSNotFound
)來暗示值缺失奏夫。Swift
的可選類型
可以讓你暗示任意類型
的值缺失
怕篷,并不需要一個特殊值。
如果你聲明一個可選常量或者變量但是沒有賦值酗昼,它們會自動被設(shè)置為 nil
:
var surveyAnswer: String?
// surveyAnswer 被自動設(shè)置為 nil
7.可選類型
使用可選類型(optionals
)來處理值可能缺失的情況廊谓。
一個可選的 Int
被寫作Int?
而不是Int
。問號暗示包含的值是可選類型麻削,也就是說可能包含 Int
值也可能不包含值蒸痹。
使用 !
來獲取一個不存在的可選值
會導(dǎo)致運行時錯誤。使用!
來強制解析
值之前呛哟,一定要確定可選包含一個非nil
的值电抚。
8.可選綁定
使用可選綁定(optional binding
)來判斷可選類型是否包含值,如果包含就把值賦給一個臨時常量或者變量竖共。
可選綁定可以用在if
和 while
語句中蝙叛,這條語句不僅可以用來判斷可選類型中是否有值,同時可以將可選類型中的值賦給一個常量或者變量公给。
if let constantName = someOptional {
statements
}
理解:
“如果 Int(possibleNumber)
返回的可選 Int
包含一個值借帘,創(chuàng)建一個叫做 actualNumber
的新常量并將可選包含的值賦給它√暑恚”
如果轉(zhuǎn)換成功肺然,actualNumber
常量可以在if
語句的第一個分支中使用。它已經(jīng)被可選類型 包含的 值初始化過腿准,所以不需要再使用 !
后綴來獲取它的值际起。在這個例子中,actualNumber
只被用來輸出轉(zhuǎn)換結(jié)果吐葱。
你可以在可選綁定中使用常量和變量街望。如果你想在if語句的第一個分支中操作 actualNumber
的值,你可以改成 if var actualNumber
弟跑,這樣可選類型包含的值就會被賦給一個變量而非常量灾前。
9.隱式解析可選類型
可選類型暗示了常量或者變量可以“沒有值”∶霞可選可以通過 if
語句來判斷是否有值哎甲,如果有值的話可以通過可選綁定
來解析值蔫敲。
有時候在程序架構(gòu)中,第一次被賦值之后炭玫,可以確定一個可選類型總會有值奈嘿。在這種情況下,每次都要判斷和解析可選值是非常低效的吞加,因為可以確定它總會有值指么。
這種類型的可選狀態(tài)被定義為隱式解析可選類型
(implicitly unwrapped optionals)。把想要用作可選的類型的后面的問號(String?
)改成感嘆號(String!
)來聲明一個隱式解析可選類型
榴鼎。
可選類型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 // 不需要感嘆號
可以把隱式解析可選類型
當做一個可以自動解析
的可選類型
。你要做的只是聲明的時候把感嘆號放到類型的結(jié)尾晚唇,而不是每次取值的可選名字的結(jié)尾巫财。
10.錯誤處理
func canThrowAnError() throws {
// 這個函數(shù)有可能拋出錯誤
}
一個函數(shù)可以通過在聲明中添加throws
關(guān)鍵詞來拋出錯誤消息。當你的函數(shù)能拋出錯誤消息時, 你應(yīng)該在表達式中前置try
關(guān)鍵詞哩陕。
do {
try canThrowAnError()
// 沒有錯誤消息拋出
} catch {
// 有一個錯誤消息拋出
}
do {
try makeASandwich()
eatASandwich()
} catch SandwichError.outOfCleanDishes {
washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
buyGroceries(ingredients)
}
11.斷言
可選類型可以讓你判斷值是否存在平项,你可以在代碼中優(yōu)雅地處理值缺失的情況。然而悍及,在某些情況下闽瓢,如果值缺失或者值并不滿足特定的條件,你的代碼可能沒辦法繼續(xù)執(zhí)行心赶。這時扣讼,你可以在你的代碼中觸發(fā)一個斷言(assertion)
來結(jié)束代碼運行并通過調(diào)試來找到值缺失的原因。
使用斷言進行調(diào)試
斷言會在運行時判斷一個邏輯條件是否為 true
缨叫。從字面意思來說椭符,斷言“斷言”一個條件是否為真。你可以使用斷言來保證在運行其他代碼之前耻姥,某些重要的條件已經(jīng)被滿足销钝。如果條件判斷為 true
,代碼運行會繼續(xù)進行琐簇;如果條件判斷為 false
蒸健,代碼執(zhí)行結(jié)束,你的應(yīng)用被終止
婉商。
你可以使用全局assert(_:_:file:line:)
函數(shù)來寫一個斷言似忧。向這個函數(shù)傳入一個結(jié)果為 true
或者 false
的表達式以及一條信息,當表達式的結(jié)果為 false
的時候這條信息會被顯示:
let age = -3
assert(age >= 0, "A person's age cannot be less than zero")
// 因為 age < 0丈秩,所以斷言會觸發(fā)
在這個例子中橡娄,只有 age >= 0
為 true
的時候,即 age
的值非負的時候癣籽,代碼才會繼續(xù)執(zhí)行挽唉。如果 age
的值是負數(shù)滤祖,就像代碼中那樣,age >= 0
為 false
瓶籽,斷言被觸發(fā)匠童,終止應(yīng)用。
*注意:當代碼使用優(yōu)化編譯的時候塑顺,斷言將會被禁用汤求,例如在 Xcode 中,使用默認的 target Release 配置選項來 build 時严拒,斷言會被禁用扬绪。
當條件可能為假時使用斷言,但是最終一定要保證條件為真裤唠,這樣你的代碼才能繼續(xù)運行挤牛。斷言的適用情景:
整數(shù)類型的下標索引被傳入一個自定義下標實現(xiàn),但是下標索引值可能太小或者太大种蘸。
需要給函數(shù)傳入一個值墓赴,但是非法的值可能導(dǎo)致函數(shù)不能正常執(zhí)行。
一個可選值現(xiàn)在是 nil航瞭,但是后面的代碼運行需要一個非 nil 值诫硕。
12.基本運算符
賦值運算符
與 C 語言和 Objective-C 不同,Swift 的賦值操作并不返回任何值刊侯。
if x = y {
// 此句錯誤, 因為 x = y 并不返回任何值
}
加法運算符也可用于 String 的拼接:
"hello, " + "world" // 等于 "hello, world"
空合運算符(Nil Coalescing Operator)
空合運算符(a ?? b)將對可選類型 a 進行空判斷章办,如果 a 包含一個值就進行解封,否則就返回一個默認值 b滨彻。表達式 a 必須是 Optional 類型纲菌。默認值 b 的類型必須要和 a 存儲值的類型保持一致。.
區(qū)間運算符(Range Operators)
閉區(qū)間運算符(a...b)
定義一個包含從 a
到 b
(包括 a 和 b)的所有值的區(qū)間疮绷。
半開區(qū)間運算符:半開區(qū)間(a..<b)
定義一個從a
到 b
但不包括 b
的區(qū)間翰舌。
13.字符串
初始化空字符串 (Initializing an Empty String)
var emptyString = "" // 空字符串字面量
var anotherEmptyString = String() // 初始化方法
// 兩個字符串均為空并等價。
空字符串的判斷: .isEmpty
if emptyString.isEmpty {
print("Nothing to see here")
}
// 打印輸出:"Nothing to see here"
字符串是值類型(Strings Are Value Types)
Swift
的String
類型是值類型冬骚。
如果您創(chuàng)建了一個新的字符串椅贱,那么當其進行常量、變量賦值操作只冻,或在函數(shù)/方法中傳遞時庇麦,會進行值拷貝。
任何情況下喜德,都會對已有字符串值創(chuàng)建新副本山橄,并對該新副本進行傳遞或賦值操作
在Swift
中,所有的基本類型:整數(shù)(Integer
)舍悯、浮點數(shù)(floating-point
)航棱、布爾值(Boolean
)睡雇、字符串(string
)、數(shù)組(array
)和字典(dictionary
)饮醇,都是值類型它抱,并且在底層都是以結(jié)構(gòu)體的形式所實現(xiàn)。
Swift 編譯器會優(yōu)化字符串的使用朴艰,使實際的復(fù)制只發(fā)生在絕對必要的情況下观蓄,這意味著您將字符串作為值類型的同時可以獲得極高的性能。
使用字符(Working with Characters)
通過標明一個Character類型并用字符字面量進行賦值祠墅,可以建立一個獨立的字符常量或變量:
let exclamationMark: Character = "!"
字符數(shù)組:
let catCharacters: [Character] = ["C", "a", "t", "!", "??"]
let catString = String(catCharacters)
print(catString)
// 打印輸出:"Cat!??"
連接字符串和字符
字符串可以通過加法運算符(+
)相加在一起(或稱“連接”)創(chuàng)建一個新的字符串:
您也可以通過加法賦值運算符 (+=
) 將一個字符串添加到一個已經(jīng)存在字符串變量上:
可以用append()
方法將一個字符附加到一個字符串變量的尾部
字符串插值 (String Interpolation)
let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
// message is "3 times 2.5 is 7.5"
Unicode
Unicode 是一個國際標準侮穿,用于文本的編碼和表示。 它使您可以用標準格式表示來自任意語言幾乎所有的字符毁嗦,并能夠?qū)ξ谋疚募蚓W(wǎng)頁這樣的外部資源中的字符進行讀寫操作亲茅。
Swift
的String
和Characte
r類型是完全兼容 Unicode
標準的。
Unicode 標量(Unicode Scalars)
可擴展的字形群集(Extended Grapheme Clusters)
使用 characters
屬性的 indices
屬性會創(chuàng)建一個包含全部索引的范圍(Range
)金矛,用來在一個字符串中訪問單個字符。
插入和刪除 (Inserting and Removing)
字符串/字符可以用等于操作符(==)和不等于操作符(!=)
前綴/后綴相等 (Prefix and Suffix Equality)
14.集合類型 (Collection Types)
Swift
的Arrays
勺届、Sets
和Dictionaries
類型被實現(xiàn)為泛型集合
驶俊。
Swift
語言提供Arrays
、Sets
和Dictionaries
三種基本的集合類型用來存儲集合數(shù)據(jù)
免姿。數(shù)組(Arrays
)是有序數(shù)據(jù)的集饼酿。集合(Sets
)是無序無重復(fù)數(shù)據(jù)的集。字典(Dictionaries
)是無序的鍵值對的集胚膊。
在我們不需要改變集合的時候創(chuàng)建不可變集合是很好的實踐故俐。如此 Swift 編譯器可以優(yōu)化我們創(chuàng)建的集合。
1)數(shù)組:
創(chuàng)建一個空數(shù)組
var someInts = [Int]()
print("someInts is of type [Int] with \(someInts.count) items.")
可以使用append(_:)
方法在數(shù)組后面添加新的數(shù)據(jù)項:
使用加法賦值運算符(+=)
也可以直接在數(shù)組后面添加一個或多個擁有相同類型的數(shù)據(jù)項
shoppingList += ["Baking Powder"]
// shoppingList 現(xiàn)在有四項了
shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
// shoppingList 現(xiàn)在有七項了
調(diào)用數(shù)組的insert(_:atIndex:)
方法來在某個具體索引值之前添加數(shù)據(jù)項:
shoppingList.insert("Maple Syrup", atIndex: 0)
// shoppingList 現(xiàn)在有7項
// "Maple Syrup" 現(xiàn)在是這個列表中的第一項
類似的我們可以使用removeAtIndex(_:)方法來移除數(shù)組中的某一項紊婉。
for item in shoppingList {
print(item)
}
for (index, value) in shoppingList.enumerate() {
print("Item \(String(index + 1)): \(value)")
}
Swift
的所有基本類型(比如String
,Int
,Double
和Bool
)默認都是可哈弦┌妫化的,可以作為集合的值的類型或者字典的鍵的類型喻犁。沒有關(guān)聯(lián)值的枚舉成員值(在枚舉有講述)默認也是可哈喜燮化的。
2)集合
3)字典
字典是一種存儲多個相同類型的值的容器肢础。每個值(value)都關(guān)聯(lián)唯一的鍵(key)还栓,鍵作為字典中的這個值數(shù)據(jù)的標識符。和數(shù)組中的數(shù)據(jù)項不同传轰,字典中的數(shù)據(jù)項并沒有具體順序剩盒。我們在需要通過標識符(鍵)訪問數(shù)據(jù)的時候使用字典,這種方法很大程度上和我們在現(xiàn)實世界中使用字典查字義的方法一樣慨蛙。
Swift
的Dictionary
類型被橋接到Foundation
的NSDictionary
類辽聊。
一個字典的Key
類型必須遵循Hashable
協(xié)議纪挎,就像Set
的值類型。
var namesOfIntegers = [Int: String]()
// namesOfIntegers 是一個空的 [Int: String] 字典
namesOfIntegers[16] = "sixteen"
// namesOfIntegers 現(xiàn)在包含一個鍵值對
namesOfIntegers = [:]
// namesOfIntegers 又成為了一個 [Int: String] 類型的空字典
一個鍵值對是一個key和一個value的結(jié)合體
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
`airports`字典被聲明為變量(用`var`關(guān)鍵字)而不是常量(`let`關(guān)鍵字)因為后來更多的機場信息會被添加到這個示例字典中身隐。
作為另一種下標方法廷区,字典的updateValue(_:forKey:)
方法可以設(shè)置或者更新特定鍵對應(yīng)的值。就像上面所示的下標示例贾铝,updateValue(_:forKey:)
方法在這個鍵不存在對應(yīng)值的時候會設(shè)置新值或者在存在時更新已存在的值隙轻。和上面的下標方法不同的,updateValue(_:forKey:)
這個方法返回更新值之前的原值垢揩。這樣使得我們可以檢查更新是否成功玖绿。
可以使用下標語法來通過給某個鍵的對應(yīng)值賦值為nil
來從字典里移除一個鍵值對
:
airports["APL"] = "Apple Internation"
// "Apple Internation" 不是真的 APL 機場, 刪除它
airports["APL"] = nil
// APL 現(xiàn)在被移除了
removeValueForKey(_:)
方法也可以用來在字典中移除鍵值對。這個方法在鍵值對存在的情況下會移除該鍵值對并且返回被移除的值或者在沒有值的情況下返回nil
:
if let removedValue = airports.removeValueForKey("DUB") {
print("The removed airport's name is \(removedValue).")
} else {
print("The airports dictionary does not contain a value for DUB.")
}
// prints "The removed airport's name is Dublin Airport."
我們可以使用for-in循環(huán)來遍歷某個字典中的鍵值對叁巨。
for (airportCode, airportName) in airports {
print("\(airportCode): \(airportName)")
}
// YYZ: Toronto Pearson
// LHR: London Heathrow
通過訪問keys或者values屬性斑匪,我們也可以遍歷字典的鍵或者值:
airports.keys
和 airports.values
構(gòu)造函數(shù):
let airportCodes = [String](airports.keys)
// airportCodes 是 ["YYZ", "LHR"]
Swift
的字典類型是無序集合類型。為了以特定的順序遍歷字典的鍵或值锋勺,可以對字典的keys
或values
屬性使用sort()
方法蚀瘸。
15.函數(shù)
函數(shù)
是一段完成特定任務(wù)的獨立代碼片段
。你可以通過給函數(shù)命名來標識某個函數(shù)的功能庶橱,這個名字可以被用來在需要的時候"調(diào)用"這個函數(shù)來完成它的任務(wù)贮勃。
輸入輸出參數(shù)(In-Out Parameters)
函數(shù)參數(shù)默認是常量。試圖在函數(shù)體中更改參數(shù)值將會導(dǎo)致編譯錯誤(compile-time error)苏章。這意味著你不能錯誤地更改參數(shù)值寂嘉。如果你想要一個函數(shù)可以修改參數(shù)的值,并且想要在這些修改在函數(shù)調(diào)用結(jié)束后仍然存在枫绅,那么就應(yīng)該把這個參數(shù)定義為輸入輸出參數(shù)(In-Out Parameters)泉孩。
定義一個輸入輸出參數(shù)時,在參數(shù)定義前加 inout 關(guān)鍵字并淋。一個輸入輸出參數(shù)有傳入函數(shù)的值寓搬,這個值被函數(shù)修改,然后被傳出函數(shù)县耽,替換原來的值订咸。想獲取更多的關(guān)于輸入輸出參數(shù)的細節(jié)和相關(guān)的編譯器優(yōu)化,請查看輸入輸出參數(shù)一節(jié)酬诀。
你只能傳遞變量給輸入輸出參數(shù)脏嚷。你不能傳入常量或者字面量(literal value),因為這些量是不能被修改的瞒御。當傳入的參數(shù)作為輸入輸出參數(shù)時父叙,需要在參數(shù)名前加 & 符,表示這個值可以被函數(shù)修改。
可變參數(shù) (Variadic Parameters)
func arithmeticMean(_ numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
// returns 3.0, which is the arithmetic mean of these five numbers
arithmeticMean(3, 8.25, 18.75)
// returns 10.0, which is the arithmetic mean of these three numbers