class NamedShape{
? ? var numberOfSides: Int = 0
? ? var name: String
? ? init(name: String) {
? ? ? ? self.name = name
? ? }
?? ?
? ? func simpleDecription() -> String {
? ? ? ? return "A shape with \(numberOfSides) \(name) sides"
? ? }
}
?
// 除了儲存簡單的屬性之外,屬性可以有 getter 和 setter
?
class EquilaterTriangle: NamedShape{
? ? var sideLength: Double = 0.0
?
? ? init(sideLength: Double,name: String) {
? ? ? ? self.sideLength = sideLength
? ? ? ? super.init(name: name)
? ? ? ? numberOfSides = 3
? ? }
?
? ? var perimeter: Double {
? ? ? ? get {
? ? ? ? ? ? return 3.0 * sideLength
? ? ? ? }
?
? ? ? ? set{
? ? ? ? ? ? sideLength = newValue / 3.0
? ? ? ? }
? ? }
?
? ? override func simpleDecription() -> String {
? ? ? ? return "An equilateral triagle with sides of length \(sideLength)"
? ? }
?
}
?
var triangle = EquilaterTriangle.init(sideLength: 3.1, name: "a triangle")
print(triangle.perimeter)
triangle.perimeter = 9.9
print(triangle.sideLength)
?
// 在 perimeter 的 setter 的方法中 新值的名稱是 newValue , 你可以在 set 之后顯式的設置一個名稱
?
// 處理變量的可選值時候,你可以在操作 (比如方法,屬性 和 子腳本) 之前加 ? ,如果 ? 之前的值是nil. ? 之后的東西都會被忽略, 并且整個表達式返回nil, 否則, 并且整個表達式返回的東西都會被運行, 這兩種情況下,整個表達式的值也是一個可選值
?
let optionalSquare: EquilaterTriangle? = EquilaterTriangle.init(sideLength: 3.2, name: "houdehcneg")
let sidelength = optionalSquare?.sideLength
print(sidelength!)
?
?
// 枚舉和結構體
// 使用 enum 來創建一個枚舉,就像類和其他所有命名類型一樣,枚舉可以包含方法
?
enum Rank: Int{
? ? case Ace = 1
? ? case Two,Three,Four,Five,Six,Seven,Eight,Nine,Ten
? ? case Jack,Queen,King
? ? func simleDescription() -> String {
? ? ? ? switch self {
? ? ? ? case .Ace:
? ? ? ? ? ? return "ace"
? ? ? ? case .Jack:
? ? ? ? ? ? return "jack"
? ? ? ? case .Queen:
? ? ? ? ? ? return "queen"
? ? ? ? case .King:
? ? ? ? ? ? return "king"
? ? ? ? default:
? ? ? ? ? ? return String(self.rawValue)
? ? ? ? }
? ? }
}
?
let ace = Rank.Ace
let aceRawValue = ace.rawValue
print(ace,aceRawValue)
?
// 默認情況下, Switch 按照從 0 開始每次加 1 的方式為原始值進行賦值,不過你可以通過顯式賦值進行改變,在上面的例子中,ace 被顯式賦值為 1 ,并且剩下的原始值會按照順序賦值,你也可以使用字符串或者浮點數作為枚舉的原始值,使用 rawValue 屬性來訪問一個枚舉成員的原始值
?
?
// 協議和擴展
// 使用 protocol 來聲明一個協議
protocol ExampleProticol{
? ? var simpleDescription: String { get }
? ? mutating func adjust()
?? ?
}
?
// 類,枚舉和結構體都可以實現協議
class SimpleClass: ExampleProticol{
? ? var simpleDescription: String = "A very simple class"
? ? var anotherProperty: Int = 69105
? ? func adjust() {
? ? ? ? simpleDescription += " Now 100% adjusted"
? ? }
}
?
var a = SimpleClass.init()
a.adjust()
let aDescription = a.simpleDescription
print(aDescription)
?
?
struct SimpleStructure: ExampleProticol{
? ? var simpleDescription: String = "A simple structure"
? ? mutating func adjust() {
? ? ? ? simpleDescription += "(adjusted)"
? ? }
}
?
var b = SimpleStructure.init()
b.adjust()
let bDescription = b.simpleDescription
print(bDescription)
?
// 注意聲明 simpleStrcture 時候 mutating 關鍵字用來標記一個會修改結構體的方法, SimpleClass 的聲明不需要標記任何方法, 因為類中的方法通常可以修改類屬性 (類的性質)
?
?
// 使用 extension 來為現有的類型添加功能, 比如新的方法和計算屬性, 你可以使用擴展在別處修改定義, 甚至是從外部庫或者框架引入一個類型, 使得這個類型遵循某個協議
?
extension Int: ExampleProticol{
? ? var simpleDescription: String {
? ? ? ? return "The number \(self)"
? ? }
?? ?
? ? mutating func adjust() {
? ? ? ? self += 42
? ? }
}
?
print(47.simpleDescription)
?
?
// 你可以\像使用其他命名類型一樣使用協議名 -- 例如, 創建一個有不同類型但是都實現一個協議的對象集合, 當你處理類型是協議的值時, 協議外定義的方法不可用
?
// 即使 protocolValue 變量運行的類是 simpleClass ,編輯器會把它的類型當做 ExampleProtocol , 這表示你不能調用類在他實現的協議之外實現的方法或者屬性
?
?
?
// 錯誤類型
// 使用采用 Error 協議的類型來表示錯誤
enum PrinterError: Error{
? ? case OutOfPaper
? ? case NoToner
? ? case OnFire
}
?
// 使用 throw 來拋出一個錯誤并使用 throws 來表示一個可以拋出錯誤的函數,如果在函數中拋出一個錯誤, 這個函數會立即返回并調用函數的代碼進行錯誤處理
?
func send(job: Int, toPrinter printerName: String) throws -> String{
? ? if printerName == "New Has Toner" {
? ? ? ? throw PrinterError.NoToner
? ? }
? ? return "Job sent"
}
?
// 有很多種方式可以進行錯誤處理 一種方式是使用 do-catch , 在 do 代碼塊中,使用 try 來標記可以拋出錯誤的代碼 , 在 catch 代碼塊中 , 除非你重新命名 , 否則錯誤會被自動命名 error
?
do {
? ? let printerResponse = try send(job: 1040, toPrinter: "Bi Sheng")
? ? print(printerResponse)
?? ?
} catch? {
? ? print(error)
}
?
?
// 泛型
// 在尖括號里寫一個名字來創建一個泛型函數或者類型
func repeatItem<Item>(repeating item: Item, numberOfTime: Int) ->[Item] {
? ? var result = [Item]()
? ? for _ in 0 ..< numberOfTime{
? ? ? ? result.append(item)
? ? }
? ? return result
}
?
repeatItem(repeating: "knock", numberOfTime: 4)
?
// 也可以創建泛型函數,方法 ,類 ,枚舉 , 和結構體
?
// 在類型后面使用 where 來指定對類型的需求 , 比如 , 限定類型實現某一個協議, , 限定兩個類型是相同的,? 或者限定某個類必須有一個特定的父類
?
// Int 表示整型值,Double 和 Float 表示浮點型值, Bool 表示布爾型值, String 表示文本型值, Swift 還提供了三個基本的集合類型, Array, Set , Dictionary
// 與C語言一樣, Swift 使用變量來進行存儲并通過變量名來關聯值,在swift中,廣泛的使用者的值不可變的變量,他們就是常量,在swift中如果你要處理的值不需要改變,把使用常量可以讓你的代碼更加安全并且更加氫氣的表達你的意圖
?
// swift 還增加了 OC 中沒有的高階數據類型 如元組 (Tuple) ,元組可以讓你創建或者傳遞一組數據,比如作為函數返回值是,可以用元組返回多個值
?
// swift 還提供了可選 (Optional) 類型,用于處理值缺失的情況. 可選值表示 "那兒有一個值,并且它等于 x ,或者 那兒沒有值". 可選值有點像 OC 中使用 nil , 但是他可以用在任何類型上, 不僅僅是類. 可選類型比 OC 中的 nil 更加安全也更具表現力,? 它是swift許多強大的特性的重要組成部分
?
// swift 是一門類型安全的語言, 這意味這 swift 可以讓你清楚地知道值的類型, 如果你的代碼期望得到一個 String? ,類型安全會阻止你傳入一個 Int , 同樣的, 如果你的代碼期望得到一個 String , 類型安全會阻止你傳入一個可選的 String , 類型安全可以幫助你在開發階段盡早的發現并修復錯誤
?
// 常量和變量
/*
?常量和變量把一個名字 和一個指定類型的值關聯起來,常量的值一旦設定就不能改變, 而變量的值可以隨意更改
?
?聲明常量和變量
?常量和變量在使用前必須聲明, 用 let 來聲明常量, 用 var 來聲明變量
?例如 :
?let maximumNumberOfLoginAttempts = 10
?var currentLoginAttempt = 0
?這兩行代碼可以被理解為:
?聲明一個名字 maximumNumberOfLoginAttempts 的新常量, 并給他一個值 10, 然后, 聲明一個名字是 currentLoginAttempt 的變量, 他的初始值的 0?
?你可以在一行中聲明多個常量或者變量, 用逗號隔開
?
?*/
?
// 類型標注
/*
?當你聲明常量或者變量的時候可以加上類型標注, 說明變量或者常量中要存儲的值的類型, 如果要添加類型標注, 需要在常量或者變量的命名后面加上一個 冒號 和 空格 , 然后加上類型標注
?例如:
?var welcomMessage: String
?這個例子給 welcomMessage 變量添加了類型標注, 表示這個變量可以存儲 String 類型的值
?聲明中的 冒號 代表著 "是...的類型",所以這行代碼可以被理解為
?"聲明一個類型為 String , 名字為 welcomMessage 的變量"
?"類型為 String 的意思是可以存儲任意 String 類型的值"
?welcomMessage 變量可以被設置為任意類型的字符串
?你可以在一行中定義多個同樣類型的變量, 用逗號分割, 并在最后一個變量名之后添加類型標注
?
?注意:?
?一般來說很少需要些類型標注, 如果你在聲明常量或者變量的時候賦給一個初始值, Swift 可以推斷出這個常量或者變量的類型, 在上面的例子中, 沒有給welcomMessage 賦給初始值, 所以變量 welcomMessage 的類型是通過一個類型標注實現的, 而不是通過初始值推斷
?
?*/
?
// 常量和變量的命名
/*
?你可以用任何你喜歡的字符作為常量和變量名, 包括 Unicode 字符
?常量和變量名不能包含數字符號,箭頭,保留的 (或者非法的) Unicode 碼位,連線與制表符,也不能以數字開頭,可以再命名的其他位置使用數字
?一旦你將常量或者變量聲明為確定的類型, 你就不能使用相同的名字再次聲明, 或者改變其村塾值的類型. 同時, 你也不能將常量或者變量互轉
?
?你可以更改現有的變量值為其他同類型的值,
?但常量的值一旦確定就不能更改
?*/
?
// 輸出常量或者變量
/*
?可以用 print(_:separator:terminator) 函數來輸出 當前的變量或者常量的值
?print(_:separator:terminator) 是一個用來輸出一個或者多個值到適當輸出去的全局函數. 如果你用Xcode , print(_:sparator:terminator),將會輸出到 console 面板上 , separator 和 terminator 參數具有默認值, 因此你調用這個函數的時候可以忽略他們. 默認情況下, 該函數通過添加換行符來結束當前行, 如果不想換行, 可以傳遞一個空字符串給 terminator 參數- 例如 , print(someValue, terminator:"").?
?
?swift 用 字符串插值 的方式把常量名或者變量名當做占位符添加到字符串中, swift 會當前常量或者變量的值還踢這些占位符, 將常量或者變量放入 圓括號 內, 并在開括號前面使用反斜杠來將其轉義
?例如: prient("there is a \(welcomeMessage)")
?
?*/
?
?
// 注釋
/*
?swift 中的注釋C語言的注釋非常相似, 單行注釋以雙斜杠 (//) 作為起始標記
?多行注釋 /**/ 與C語言多行注釋不同的是 swift 的多行注釋可以嵌套在其他的多行注釋之中
?*/
?
?
// 分號
/*
?與其他大部分編程語言不同, swift 并不強制要求你在每條語句的結尾處使用分號 (;), 當然,你也可以按照你自己的習慣添加分號,
?有一種情況下必須使用分號, 就是你打算在同一行內寫多條獨立的語句
?*/
?
?
// 整數
/*
?整數就是沒有小數部分的數字, 整數可以有符號 ( 正, 負, 零), 或者無符號 ( 正 , 零)
?swift 提供了 8 ,16 ,32 和 64 位的有符號和無符號類型的整數, 這些整數類型和C語言的命名方式想象, 比如 8 位無符號整形整數 是 UInt8 , 32 位有符號整數類型是 Int32 ,就像 swift 的其他類型一樣 , 整數類型采用大寫命名法
?*/
?
?
// 整數范圍
/*
?你可以訪問不同的整數類型的 min 和 max 屬性來獲取對應類型的最小值和最大值
?let minValue = Uint8.min? // minValue 為 0 , 是 Uint8 類型
?let maxValue = Uint8.max? // maxValue 為 255 , 是 Uint8 類型
?
?*/
?
?
// Int?
/*
?一般來說, 你不需要專門指定整數的長度, swift 提供了一個 特殊的整數類型 Int , 長度與當前平臺的原生字長相同
?在 32 平臺上, Int 與 Int32 長度相同
?在 64 位平臺上 ,與 Int64 長度相同
?
?注意:
?盡量不要使用 Uint , 統一使用 Int 可以提高代碼的復用性 , 避免不同類型數字之間的轉換,并且匹配數字的類型判斷
?*/
?
?
// 浮點型
/*
?浮點型是有小數點的數字, 比如 3.1415926, 浮點數比整數類型表示的范圍更大, 可以存儲比 Int 類型更大或者更小的數字, swift 提供了兩種有符號浮點數類型
?Double 表示 64 位浮點數, 當你需要存儲很大的或者很高精度的浮點數是請使用此類型
?Float 表示 32 位浮點數, 精度不高的話可以使用此類型
?
?注意:
?Double 的精度很高, 至少有 15 位數字 , 而 Float 只有6 位數字,?
?在兩種類型都匹配的情況下 , 優先匹配 Double
?*/
?
?
// 類型安全和類型推斷
/*
?swift 是一門類型安全的語言, 類型安全的語言可以讓你清楚的知道代碼需要處理的值的類型嗎如果你的代碼需要一個 String ,你絕對不可能傳進去一個 Int
?
?由于swift 是類型安全的, 所以他會在編譯你的代碼的時候進行類型檢查, 并把比匹配的類型標記為錯誤.這可以讓你在開發的時候盡早發現并修復錯誤
?
?當你要處理不同類型的值時,類型檢查可以幫助你避免錯誤, 然而, 這并不是說你每次聲明產量和變量的時候都需要顯式指定類型, 如果你沒有顯式指定類型, swift 會使用類型推斷 來選擇合適的類型, 有了類型推斷 , 編譯器可以再編譯代碼的時候自動推斷出表達式的類型, 原理很簡單, 只要檢查你的賦值即可
?
?因為有類型推斷 和 C語言 和 OC 比起來 swift 很少需要聲明類型, 常量和變量雖然需要明確類型 , 但大部分工作并不需要自己來完成
?
?當你聲明常量或者變量并賦給初始值的時候類型推斷非常有用, 當你在聲明常量或者變量的時候賦給他們一個初始值即可觸發類型推斷
?
?當推斷浮點數類型的時候 swift 總是會選擇 Double 而不是 Float?
?如果表達式中同時出現整數和浮點數, 會被推斷為 Double 類型
?
?*/
?
?
// 數值型類型轉換
/*
?通常來講, 即使代碼中的整數常量和變量已知非負, 也請使用 Int 類型, 總是使用默認的整數類型可以保證你的整數常量和變量可以直接被服用并且可以匹配整數字面量的類型推斷
?*/
?
?
// 整數轉換
/*
?不同整數類型的變量和常量可以存儲不同范圍的數字, Int8 類型常量或者變量可以存儲數組的范圍 -128 ~ 127 , 而 UInt8 類型的常量或者變量能存儲的數字范圍是 0 ~ 255 , 如果超出了常量或者變量可存儲的范圍嗎編譯器會報錯
?
?由于每種整數類型都可以存儲不同范圍的值, 所以你必須根據不同情況選擇性使用數值類型轉換, 這種選擇性使用的方式, 可以預防隱式轉換的錯誤讓你的代碼中類型轉換意圖變得清晰
?
?要將一種數字類型轉換成另一種, 你要用當前值來初始化一個期望值類型的數字, 這個數字的類型就是你的目標類型,?
?
?SomeType(ofIninitiaValue) 是調用swift 構造器并傳入一個初始值的默認方法, 在語言內部, UInt16 有一個構造器, 可以接受一個 其他類型的值, 所以這個構造器可以用現在的 UInt8 來創建一個新的 UInt16?
?注意 : 比并不能傳入任意類型的值, 只能傳入 UInt16 內部有對應構造器的值, 不過你可以擴展現有的類型來讓他可以接受其他類型的值(包括自定義類型)
?
?*/
?
?
// 整數和浮點數轉換
/*
?整數和浮點數的轉化必須顯式指定類型:
?浮點數到整數反向轉換同樣可以, 整數類型可以用 Double 或者 Float 類型來初始化
?當用這種方式來初始化的時候, 浮點數會被截斷
?
?*/
?
?
// 類型別名
/*
?類型別名 (type aliases) 就是給現有的類型定義另一個名字, 你可以使用 typealias 關鍵字來定義類型別名
?當你想要給現有的類型起一個更有意義的名字的時候, 類型別名非常有用
?例如:
?typealias AudioSample = UInt16
?定義了一個類型別名之后, 你可以在任何使用原始名的地方使用別名:
?var maxAmplitudeFound = AudioSample.min
?
?*/
?
?
// 布爾值
/*
?swift 有一個基本的布爾值類型, 叫做 Bool ,布爾值指邏輯上的值, 因為他們只能是真或者假, swift 有兩個布爾值常量, true 和 false?
?let orangesAreOrange = true
?let turnipsAreDelicius = false
?
?這兩個值的類型會被推斷為 Bool , 因為他們的初始值是布爾值常量, 就像之前提到的 Int 和? Double 一樣, 如果你創建變量的時候賦值 true 和 false , 那你不需要講常量和變量聲明為: Bool 類型, 初始化常量或者變量的時候如果所賦值類型已知, 你就可以出發類型推斷, 這讓swift 代碼更加簡潔而且可讀性更高
?
?*/
?
?
// 元組
/*
?元組 (tuples) 把多個值組合成一個復合值, 元組內的值可以是任意類型, 并不要求是相同類型
?你可以把任意類型,任意順序的值組合成一個元組, z這個元組可以包含所有類型
?
?*/
let http404Error = (404, "Not Found")
?
// 你可以講一個元組的內容分解成單獨的常量和變量,然后就可以正常使用它們了
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
print("The status message is \(statusMessage)")
?
// 如果你只需要一部分元組的值 , 分解的時候可以把忽略的部分用下劃線 (_) 標記"
let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
?
// 此外, 你也可以通過下標來訪問元組中的單個元素
print("The status code is \(http404Error.0)")
print("The status message is \(http404Error.1)")
?
// 你可以在定義元組的時候給單個元素命名,然后通過名字來獲取這些元素的值
let http200Sattus = (statusCode: 200, description: "OK")
print("The status code is \(http200Sattus.statusCode)")
print("The status message is \(http200Sattus.description)")
?
// 作為函數返回值, 元組非常有用,?
// 注意: 元組在臨時組織值的時候很有用,但是并不適合復雜的數據結構, 如果你的數據結構并不是臨時使用的, 請使用類或者結構體,而不是元組
?
?
// 可選類型
/*
?使用可選類型 (optional) 來處理值缺失的情況, 可選值表示: 有值, 等于 X, 或者 沒有值
?注意:
?C 和 OC 中并沒有可選類型的概念, 最接近的是 OC 中的一個特性, 一個方法要不返回一個對象要不返回nil, nil表示 "缺少一個合法的對象", 然而 這只對對象起作用,基本的 C 類型或者枚舉類型不起作用, 對于這些類型, OC 方法一般會返回一個特殊值 (比如 NSNotFound) 來暗示值缺失, 這種方法假設方法的調用者知道并記得對特殊值進行判斷, 然而, swift 的可選類型可以讓你暗示任意類型的值缺失, 并不需要一個特殊值
*/
?
// 例如:
// swift 的 Int 類型 有一種構造器, 作用是將一個 String 值轉換成一個 Int 值, 然而, 并不是所有的字符串都可以轉換成一個整數, 字符串 "123" 可以被轉換成123 ,但是字符串 "Hello world" 顯然不行
?
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
print(convertedNumber!)
?
let hw = "Hello world"
let hwi = Int(hw)
// 因為該構造器可能失敗 , 所以他返回一個可選類型 (optional) Int , 而不是一個 Int , 一個可選的 Int 被寫作 Int? 而不是 Int , 問好暗示包含的值是可選類型, 也就是說可能包含 Int 值 也很能不包含值, (不能包含其他不類型的值, 只能是 Int 或者什么都沒有)
?
// 可以給可選變量賦值為 nil 來表示他沒有值
var severResponseCode: Int? = 404
severResponseCode = nil
?
// 注意:
// nil 不能用于非可選的常量或者變量, 如果你的代碼中有常量或者變量需要處理值缺失的情況, 請把他們聲明成對應的可選類型
// 如果你聲明一個可選常量或者變量但沒有賦值, 他們會被自動設置為 nil?
var summ :String? // summ 會被自動設置為nil
?
// 注意:
// swift 的nil 和 OC 中的nil 并不一樣, 在 OC 中, nil 是一個指向不存在對象的指針, 在swift 中, nil 不是指針 -- 它是一個確定的值, 用來表示值缺失的, 任意類型的可選狀態都可以被設置為 nil ,不只是對象類型
?
?
// if 語句以及強制解析
/*
?你可以使用 if 語句和 nil 比較 來判斷一個可選值是否包含值. 你可以使用 (==) or (!=) 來執行比較, 如果可選類型有值,它將不等于 nil
?當你確定可選類型的確實包含值之后, 你可以在可選的名字后面 添加一個 (!) 來獲取值 , 這個 (!) 的意思是 "我知道這個可選有值, 請使用它.", 這被稱為可選值的 '強制解析'
?注意:
?使用 ! 來獲取一個不存在的可選值會導致運行時報錯. 使用 ! 來強制解析值之前 , 一定要確定可選值包含一個非 nil 的值
*/
?
?
// 可選綁定
/*
?使用可選綁定 (optional binding) 來判斷可選類型是否包含值, 如果包含就把包含值賦給一個臨時常量或者變量, 可選綁定可以用在 if 和 while 語句中, 這條語句不僅可以用來判斷可選類型中是否有值, 同事可以將可選類型中的值賦給一個常量或者變量.
?*/
?
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 包含一個值, 創建一個叫做 actualNumber 的新常量并將可選類型包含的值賦給它
// 如果轉換車成功, actualNumber 常量可以在 if 語句的第一個分支中使用, 他已經被可選類型包含的值初始化過, 所以不需要再使用 ! 后綴來獲取他的值. 在這個例子中, actualNumber 只是用來輸出轉換結果
// 你可以在可選綁定中使用常量或者變量, 如果你想在 if 語句的第一個分支中操作 actualNumber 的值, 你可以改成 ' if var actualNumber ' , 這樣可選類型包含的值會被賦給一個變量而非常量
?
// 注意:
// 在 if 語句中使用常量或者變量來創建一個可選綁定, 僅在 if 語句的句中(body)中才能取到值, 相反 , 在 guard 語句中使用常量和變量來創建一個可選綁定, 僅在 guard 語句外且在語句后才能取到值
?
?
// 隱式解析可選類型
/*
?如上所述, 可選類型暗示了常量或者變量可以 "沒有值", 可選可以通過 if 語句來判斷是否有值, 如果有值的話可以通過可選綁定來解析
?
?有時候在程序架構中, 第一次被賦值之后, 可以確定一個可選類型總會有值, 在這種情況下, 每次都要判斷和解析可選值是非常低效的, 因為可以確定他總會有值
?
?這種類型的可選狀態定義為隱式解析可選類型 (implicitly unwrapped optionals) . 把想要用作可選的類型的后面的 問號 (String?) 改成 (String!) 來聲明一個隱式解析可選類型
?
?當可選類型被第一次賦值之后就可以確定之后一直有值的時候, 隱式解析可選類型非常有用, 隱式解析可選類型主要被用在 swift 中類的構造過程中
?
?一個隱式解析可選類型其實就是一個普通的可選類型, 但是可以被當做非可選類型來使用
?.并不需要每次都使用解析來獲取可選值,
?*/
?
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // 需要感嘆號來取值
?
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString
?
// 你可以把隱式可選類型當做一個自動解析的可選類型. 你要做的只是聲明的時候把 感嘆號 放到類型的結尾, 而不是每次取值的可選名字的結尾
?
// 注意:
// 如果你在隱式解析可選類型沒有值的實收嘗試取值, 會觸發運行時錯誤, 和你在沒有值的時候在普通的可選類型后面加一個 驚嘆號 一樣
?
// 你仍然可以把隱式解析可選類型當做普通可選類型來判斷他是否有值
// 你也可以可選綁定中使用隱式解析可選類型來檢查并解析他的值
?
// 注意:
// 如果一個變量之后可能變成 nil 的話請不要使用隱式解析可選類型. 如果你需要在變量的生命周期中判斷是否是 nil 的話, 請使用普通可選類型
?
?
// 錯誤處理
/*
?你可以使用錯誤處理 (error handing) 來應對程序執行中可能出現的錯誤條件
?
?相對于可選中運行值的存在與缺失來表達函數的成功與失敗, 錯誤處理可以判斷失敗的原因, 并傳播至程序的其他部分, 當一個函數遇到錯誤條件, 他能報錯, 調用函數的地方能拋出錯誤消息并合理處理
?
?*/
?
func canThrowAnReeor() throws{
? ? // 這個函數有可能拋出錯誤
}
?
// 一個函數可以通過在聲明中添加 throws 關鍵字來拋出錯誤消息. 當你的函數能拋出錯誤消息是, 你應該在表達式中前置 try 關鍵字
?
do {
? ? try canThrowAnReeor()
? ? // 沒有錯誤消息拋出
} catch? {
? ? // 有一個錯誤消息拋出
}
?
// 一個 do 語句創建了一個新的包含作用域, 使得錯誤能被傳播到一個或者多個 catch 從句
// 例如:
?
func makeASandwich() throws {
?? ?
}
?
// 例如:
?
//do {
//? ? try makeASandwich()
//? ? eatASandwich()
//} catch SandwichError.outOfCleanDishes {
//? ? washDishes()
//} catch SandwichError.missingIngredients(let ingredients) {
//? ? buyGroceries(ingredients)
//}
?
// 在此例中, makeAsanwich() (做一個三明治) 函數會拋出一個錯誤消息如果消息沒有干凈的盤子或者某個原料缺失, 因為 makeASanwich() 拋出錯誤, 函數調用被包裹在 try 表達式中, 將函數包裹在一個 do 語句中, 任何被拋出的錯誤會被傳播到 catch 從句中
?
// 如果沒有錯誤被拋出, eatASanwich() 函數被執行, 如果一個匹配 SandwichError.outOfCleanDishes 的錯誤被拋出 washDishes() 函數會被調用, 如果一個匹配 SandwichError.missingIngredients 的錯誤被拋出, buyGroceries(_:) 函數會被調用, 并且 catch 所捕捉得到的關鍵值 [String] 作為參數
?
?
// 斷言
// 可選類型可以讓你判斷值是否存在,? 你可以在代碼中優雅地處理值缺失的情況, 然而 , 在某些情況下. 如果值缺失或者值并不滿足特定的條件,你的代碼可能沒有辦法運行, 這時候 . 你可以在您的代碼中觸發一個 斷言 (assertion) 來結束代碼運行并通過調試來找到值確實的情況
?
// 使用斷言進行調試
// 斷言會在運行時判斷一個邏輯條件是否為 true , 從字面意思來說, 斷言 "斷言" 一個條件是否為真, 你可以使用斷言來保證在運行其他代碼之前, 某些重要的條件已經被滿足, 如果條件判斷為 true , 代碼運行會被繼續, 如果條件判讀為 false , 代碼執行結束, 你的應用被終止
?
// 如果你的代碼在調試環境下觸發了一個斷言. 比如你在 Xcode 構建并運行了一個應用, 你可以清楚地看到不合法的狀態發生在哪里并檢查被觸發時你的應用的狀態, 此外, 斷言允許你附加一條調試信息
?
// 你可以使用全局 assert(_:_:flie:line:)函數來寫一個斷言,想這個函數傳入一個結果為 true 或者 false 的表達式以及一條信息, 當表達式的結果為 false 的時候這條信息會被顯示
?
let age = 3
assert(age >= 0, "A person's age cannot be less than zero")
?
// 在這個例子中, 只有 age >= 0 為 true 的時候, 即 age 的值非負的時候, 代碼才會繼續執行, 如果 age 的值是負數, 就想代碼中那樣, age >= 0 為 false ,斷言被觸發, 終止應用
// 如果不需要斷言信息? 可以省略
assert(age >= 0)
?
// 注意: 當代碼使用優化編譯的時候, 斷言將會被禁用, 例如在Xcode 中, 使用默認的target Release 配置選項來 build 時候, 斷言會被禁用
?
// 何時使用斷言
// 當條件可能為假的時候使用斷言, 但是最終一定要保證條件為真, 這樣你的代碼才能繼續運行
// 斷言的適用場景
/*
?1. 整數類型的下標索引被傳入一個自定義下標實現, 但是下標索引值可能太大或者太小
?2. 需要函數傳入一個值, 但是非法的值可能導致函數不能正常運行
?3. 一個可選值現在是 nil, 但是后面的代碼運行需要一個非 nil 的值
?
?注意:
?斷言可能導致你的應用終止, 所以你應當仔細設計你的代碼來讓非法條件不會出現, 然而, 當你的應用發布之后, 有時候非法條件出現, 這時使用斷言可以快速發現問題
?
?*/