YES
- 2014WWDC發(fā)布
常量和變量使用注意
- 在實(shí)際過(guò)程中,建議先定義常量,如果需要修改再改變?yōu)樽兞?更加安全)
- 可以在一行中聲明多個(gè)常量或者多個(gè)變量,用逗號(hào)隔開(kāi)
var x = 0.0, y = 0.0, z = 0.0
var red, green, blue: Double
類(lèi)型標(biāo)注
- 如果要添加類(lèi)型標(biāo)注,需要在常量或者變量名后面加上一個(gè)冒號(hào)和空格,然后加上類(lèi)型名稱(chēng)
- 如果你需要使用與Swift保留關(guān)鍵字相同的名稱(chēng)作為常量或者變量名,你可以使用反引號(hào)(`)將關(guān)鍵字包圍的方式將其作為名字使用。無(wú)論如何,你應(yīng)當(dāng)避免使用關(guān)鍵字作為常量或變量名,除非你別無(wú)選擇
整數(shù)范圍
- 你可以訪問(wèn)不同整數(shù)類(lèi)型的 min 和 max 屬性來(lái)獲取對(duì)應(yīng)類(lèi)型的最小值和最大值:
- 即使是在32位平臺(tái)上,Int 可以存儲(chǔ)的整數(shù)范圍也可以達(dá)到 -2,147,483,648 ~ 2,147,483,647 ,大多數(shù)時(shí)候這已經(jīng)足夠大了
浮點(diǎn)數(shù)
- Double精確度很高,至少有15位數(shù)字,而Float只有6位數(shù)字。選擇哪個(gè)類(lèi)型取決于你的代碼需要處理的值的范圍,在兩種類(lèi)型都匹配的情況下,將優(yōu)先選擇 Double。
- 整數(shù)和浮點(diǎn)數(shù)都可以添加額外的零并且包含下劃線,并不會(huì)影響字面量:
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1
- 通常來(lái)講,即使代碼中的整數(shù)常量和變量已知非負(fù),也請(qǐng)使用Int類(lèi)型
- 當(dāng)用這種方式來(lái)初始化一個(gè)新的整數(shù)值時(shí),浮點(diǎn)值會(huì)被截?cái)唷R簿褪钦f(shuō) 4.75 會(huì)變成 4,-3.9 會(huì)變成 -3。
類(lèi)型推倒
- swift屬于強(qiáng)類(lèi)型語(yǔ)言,任何一個(gè)標(biāo)示符都有明確的類(lèi)型
- 如果定義一個(gè)標(biāo)示符時(shí)有直接進(jìn)行賦值,那么標(biāo)示符后面的類(lèi)型可以省略,因?yàn)閟wift有類(lèi)型推導(dǎo),會(huì)自動(dòng)根據(jù)后面的賦值來(lái)決定前面標(biāo)示符的數(shù)據(jù)類(lèi)型
- option + 鼠標(biāo)左鍵 可以查看變量類(lèi)型
類(lèi)型別名
- 類(lèi)型別名(type aliases)就是給現(xiàn)有類(lèi)型定義另一個(gè)名字。你可以使用typealias關(guān)鍵字來(lái)定義類(lèi)型別名
輸出常量和變量
- Swift 用字符串插值(string interpolation)的方式把常量名或者變量名當(dāng)做占位符加入到長(zhǎng)字符串中,Swift 會(huì)用當(dāng)前常量或變量的值替換這些占位符。將常量或變量名放入圓括號(hào)中,并在開(kāi)括號(hào)前使用反斜杠將其轉(zhuǎn)義
基本運(yùn)算
- 沒(méi)有隱式轉(zhuǎn)換,必須保證類(lèi)型一致
邏輯分支
- if else
- if 后面的小括號(hào)可以省略
- 判斷句必須有明確的真假
- 三目運(yùn)算符 與OC 形同
- switch 語(yǔ)句
- switch后面的小括號(hào)可以省略
- case語(yǔ)句結(jié)束后的break也可以省略
- 如果需要穿透可以在case 語(yǔ)句后面跟上fallthrough
- case后面可以判斷多個(gè)條件,用 逗號(hào) 分隔
- switch可以判斷浮點(diǎn)型 字符串
- switch 可以判斷區(qū)間 開(kāi)區(qū)間 0..<10 不包括 10 0...10 包括10
for循環(huán)
- forin
for i in 0..<10{
print(i)
}
for _ in 0..10{
}
while 循環(huán)
var c = 10
while c > 11 {
// 自增自減?????
print("大于0")
}
dowhile
repeat {
statements
} while condition
字符串
- String 是一個(gè)結(jié)構(gòu)體,性能更高
- String支持直接遍歷
- swift提供了String 和 NSString之間的無(wú)縫轉(zhuǎn)換
let age = 28
let info = "my name is \(name),my age is \(age)"
// 拼接字符串時(shí)的格式化
let min = 2
let sec = 3
let timestring = String.init(format: "%02d:%02d", arguments:[min,sec])
let substr = (timestring as NSString).substring(to: 3)
數(shù)組
- 創(chuàng)建一個(gè)空數(shù)組 var someInts = Int
- 創(chuàng)建一個(gè)帶有默認(rèn)值的數(shù)組
var threeDoubles = Array(repeating: 0.0, count: 3)
// threeDoubles 是一種 [Double] 數(shù)組,等價(jià)于 [0.0, 0.0, 0.0]
- 通過(guò)兩個(gè)數(shù)組相加創(chuàng)建一個(gè)數(shù)組 +
- 使用布爾屬性isEmpty作為一個(gè)縮寫(xiě)形式去檢查count屬性是否為0:
- 也可以使用append(_:)方法在數(shù)組后面添加新的數(shù)據(jù)項(xiàng)
- 如果我們同時(shí)需要每個(gè)數(shù)據(jù)項(xiàng)的值和索引值,可以使用enumerated()方法來(lái)進(jìn)行數(shù)組遍歷。enumerated()返回一個(gè)由每一個(gè)數(shù)據(jù)項(xiàng)索引值和數(shù)據(jù)值組成的元組。我們可以把這個(gè)元組分解成臨時(shí)常量或者變量來(lái)進(jìn)行遍歷:
for (index, value) in shoppingList. enumerated() {
print("Item \(String(index + 1)): \(value)")
}
集合
- 集合(Set)用來(lái)存儲(chǔ)相同類(lèi)型并且沒(méi)有確定順序的值。當(dāng)集合元素順序不重要時(shí)或者希望確保每個(gè)元素只出現(xiàn)一次時(shí)可以使用集合而不是數(shù)組
- var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
// favoriteGenres 被構(gòu)造成含有三個(gè)初始值的集合 - Swift 的Set類(lèi)型沒(méi)有確定的順序,為了按照特定順序來(lái)遍歷一個(gè)Set中的值可以使用sorted()方法,它將返回一個(gè)有序數(shù)組,這個(gè)數(shù)組的元素排列順序由操作符'<'對(duì)元素進(jìn)行比較的結(jié)果來(lái)確定.
- 集合運(yùn)算
- 使用intersection(_:)方法根據(jù)兩個(gè)集合中都包含的值創(chuàng)建的一個(gè)新的集合。
- 使用symmetricDifference(_:)方法根據(jù)在一個(gè)集合中但不在兩個(gè)集合中的值創(chuàng)建一個(gè)新的集合。
- 使用union(_:)方法根據(jù)兩個(gè)集合的值創(chuàng)建一個(gè)新的集合。
- 使用subtracting(_:)方法根據(jù)不在該集合中的值創(chuàng)建一個(gè)新的集合。
let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]
oddDigits.union(evenDigits).sorted()
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
oddDigits. intersection(evenDigits).sorted()
// []
oddDigits.subtracting(singleDigitPrimeNumbers).sorted()
// [1, 9]
oddDigits. symmetricDifference(singleDigitPrimeNumbers).sorted()
// [1, 2, 9]
let houseAnimals: Set = ["??", "??"]
let farmAnimals: Set = ["??", "??", "??", "??", "??"]
let cityAnimals: Set = ["??", "??"]
houseAnimals.isSubset(of: farmAnimals)
// true
farmAnimals.isSuperset(of: houseAnimals)
// true
farmAnimals.isDisjoint(with: cityAnimals)
// true
字典
- 創(chuàng)建字典
var dict = [String : AnyObject]()
- 和數(shù)組一樣,我們可以通過(guò)字典的只讀屬性count來(lái)獲取某個(gè)字典的數(shù)據(jù)項(xiàng)數(shù)量
- 使用布爾屬性isEmpty作為一個(gè)縮寫(xiě)形式去檢查count屬性是否為0
- ,字典的updateValue(_:forKey:)方法可以設(shè)置或者更新特定鍵對(duì)應(yīng)的值
- 如果我們只是需要使用某個(gè)字典的鍵集合或者值集合來(lái)作為某個(gè)接受Array實(shí)例的 API 的參數(shù),可以直接使用keys或者values屬性構(gòu)造一個(gè)新數(shù)組
let airportCodes = [String](airports.keys)
// airportCodes 是 ["YYZ", "LHR"]
let airportNames = [String](airports.values)
// airportNames 是 ["Toronto Pearson", "London Heathrow"]
- 遍歷字典 forin keys values
- 遍歷所有鍵值
for (key , value) in dictm{
}
- 合并字典:即使類(lèi)型一致也不能相加合并
元組
*元組的基本寫(xiě)法
let info = ("lili",18,1.88)
info.0
info.1
- 給元組的每個(gè)元素起一個(gè)別名
let info = (name :"lili",age : 18,height : 1.88)
info.name
info.age
- 元組中元素的別名,就是元組的名稱(chēng)
let (name,age,height) = ("lili",18,1.88)
forin
- 使用 stride(from:to:by:) 函數(shù)跳過(guò)不需要的標(biāo)記。
let minuteInterval = 5
for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
// 每5分鐘呈現(xiàn)一個(gè)刻度線 (0, 5, 10, 15 ... 45, 50, 55)
}
可以在閉區(qū)間使用 stride(from:through:by:) 起到同樣作用:
let hours = 12
let hourInterval = 3
for tickMark in stride(from: 3, through: hours, by: hourInterval) {
// 每3小時(shí)呈現(xiàn)一個(gè)刻度線 (3, 6, 9, 12)
}
可選類(lèi)型
定義可選類(lèi)型
- 方法一 不常用
* var name : Optional<String> = nil
* var name : String? = nil
- 如果你聲明一個(gè)可選常量或者變量但是沒(méi)有賦值,它們會(huì)自動(dòng)被設(shè)置為 nil
var surveyAnswer: String?
// surveyAnswer 被自動(dòng)設(shè)置為 nil
- Swift 的 nil 和 Objective-C 中的 nil 并不一樣。在 Objective-C 中,nil 是一個(gè)指向不存在對(duì)象的指針。在 Swift 中,nil 不是指針——它是一個(gè)確定的值,用來(lái)表示值缺失。任何類(lèi)型的可選狀態(tài)都可以被設(shè)置為 nil,不只是對(duì)象類(lèi)型。
- 注意:強(qiáng)制解包是非常危險(xiǎn)的,如果可選類(lèi)型為nil,強(qiáng)制解包系統(tǒng)會(huì)崩潰
建議:在前置解包前,先對(duì)可選類(lèi)型進(jìn)行判斷,判斷是否nil
if name != nil {
print(name!)
}```
* 可選綁定
* 判斷name是否有值,如果沒(méi)有值,直接不執(zhí)行{}
* 如果name有值,系統(tǒng)會(huì)自動(dòng)將name進(jìn)行強(qiáng)制解包,并且將解包后的結(jié)果賦值給name
if let name = name {
print(name)
}
* 你可以在可選綁定中使用常量和變量。如果你想在if語(yǔ)句的第一個(gè)分支中操作 actualNumber 的值,你可以改成 if var actualNumber,這樣可選類(lèi)型包含的值就會(huì)被賦給一個(gè)變量而非常量。
### 隱式解析可選類(lèi)型
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // 需要感嘆號(hào)來(lái)獲取值
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // 不需要感嘆號(hào)
### 錯(cuò)誤處理
* 當(dāng)一個(gè)函數(shù)遇到錯(cuò)誤條件,它能報(bào)錯(cuò)。調(diào)用函數(shù)的地方能拋出錯(cuò)誤消息并合理處理。
func makeASandwich() throws {
// ...
}
do {
try makeASandwich()
eatASandwich()
} catch SandwichError.outOfCleanDishes {
washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
buyGroceries(ingredients)
}
NO
### 字符串
* 判斷是否為""
if emptyString.isEmpty {
print("Nothing to see here")
}
* 字符串插值:您插入的字符串字面量的每一項(xiàng)都在以反斜線為前綴的圓括號(hào)中:
let multiplier = 3
let message = "(multiplier) times 2.5 is (Double(multiplier) * 2.5)"
// message 是 "3 times 2.5 is 7.5"
* 如果想要獲得一個(gè)字符串中Character值的數(shù)量,可以使用字符串的characters屬性的count屬性:
*
greeting[greeting.endIndex] // error
greeting.index(after: endIndex) // error
## Array
let oddNumbers = [1,3,5,7]
* 創(chuàng)建空數(shù)組
* var emptyDoubles : [Double] = []
* The full type name is also allowed
var emptyFloats: Array<Float> = Array()
* 如果你需要一個(gè)使用默認(rèn)值提前初始化的數(shù)組
let digitCounts = Array(repeatElement(0, count: 10))
### 比較運(yùn)算符
* 注意: Swift 也提供恒等(===
)和不恒等(!==
)這兩個(gè)比較符來(lái)判斷兩個(gè)對(duì)象是否引用同一個(gè)對(duì)象實(shí)例。
### 空合運(yùn)算符
* a ?? b 表述的意思:a != nil ? a! : b
###元組比較
* Swift 標(biāo)準(zhǔn)庫(kù)只能比較七個(gè)以內(nèi)元素的元組比較函數(shù)。如果你的元組元素超過(guò)七個(gè)時(shí),你需要自己實(shí)現(xiàn)比較運(yùn)算符。
* 因?yàn)?Int 和 String 類(lèi)型的值可以比較,所以類(lèi)型為 (Int, String) 的元組也可以被比較。
### 區(qū)間運(yùn)算符
* 閉區(qū)間運(yùn)算符: 閉區(qū)間運(yùn)算符(a...b)定義一個(gè)包含從 a 到 b(包括 a 和 b)的所有值的區(qū)間。a 的值不能超過(guò) b
* 半開(kāi)區(qū)間運(yùn)算符:半開(kāi)區(qū)間運(yùn)算符(a..<b)定義一個(gè)從 a 到 b 但不包括 b 的區(qū)間。 之所以稱(chēng)為半開(kāi)區(qū)間,是因?yàn)樵搮^(qū)間包含第一個(gè)值而不包括最后的值。
### 邏輯組合運(yùn)算符
* Swift 邏輯操作符 && 和 || 是左結(jié)合的,這意味著擁有多元邏輯操作符的復(fù)合表達(dá)式優(yōu)先計(jì)算最左邊的子表達(dá)式。
* 數(shù)組遍歷
let streets = ["mahadun","newyork"]
for street in streets {
print("I don't live on \(street).")
}
* 判斷數(shù)組是否為空 isEmpty
if oddNumbers.isEmpty {
print("數(shù)組為空")
}else{
print("i know(oddNumbers.count) odd Numbers")
}
* 取到數(shù)組的第一個(gè) 最后一個(gè)元素 ,如果數(shù)組為空,返回nil
if let firstElement = oddNumbers.first , let lastelement = oddNumbers.last {
print(firstElement, lastelement, separator: ", ")
}
* 利用角標(biāo)訪問(wèn)數(shù)組元素,不在 0..<count 會(huì)報(bào)數(shù)組越界錯(cuò)誤
* 增加或者刪除數(shù)組元素
var students = ["ben","ivy","jodell"]
// 添加單個(gè)元素 append(_:) 一次添加多個(gè)元素 append(contentsOf:)
students.append("maxi")
students.append(contentsOf: ["shaki","william"])
// 插入一個(gè)或多個(gè)元素
students.insert("liam", at: 3)
// 刪除元素
students.remove(at: 0)
// 刪除最后一個(gè)
students.removeLast()
* 修改元素
students[0] = "dddd"
**當(dāng)數(shù)組元素的個(gè)數(shù)超過(guò)初始容量,數(shù)組會(huì)將分配更大的內(nèi)存區(qū)域并將其元素復(fù)制到新存儲(chǔ)中。新存儲(chǔ)空間是舊存儲(chǔ)容量的倍數(shù)**
* 修改數(shù)組的副本copy
* 如果數(shù)據(jù)類(lèi)型為int 結(jié)構(gòu)體類(lèi)型,修改原數(shù)組內(nèi)容不會(huì)影響副本的內(nèi)容
var numbers = [1, 2, 3, 4, 5]
var numbersCopy = numbers
numbers[0] = 100
print(numbers)
// Prints "[100, 2, 3, 4, 5]"
print(numbersCopy)
// Prints "[1, 2, 3, 4, 5]"
* 如果數(shù)組元素是對(duì)象
class InergerReference{
var value = 10
}
var firstIntegers = [InergerReference(),InergerReference()]
var secondInergers = firstIntegers
firstIntegers[0].value = 100
print(firstIntegers[0].value,secondInergers[0].value)
// 100 100
firstIntegers[0] = InergerReference()
print(firstIntegers[0].value,secondInergers[0].value)
// 10 100
* Array 與 NSArray的轉(zhuǎn)換 用as
## Dictionary
* 如何創(chuàng)建一個(gè)空字典
var emptyDict: [String : String] = [:]
* 通過(guò)key來(lái)取值 取出來(lái)的值我可選項(xiàng)
print(dictionary[200] ?? "")
if let message = dictionary[500]{
print(message)
}else{
print("meiyou改制")
}```
- 添加/修改鍵值對(duì)
dictionary[100] = "text" - 對(duì)已經(jīng)存在的鍵賦值nil,改鍵值對(duì)會(huì)被移除
var interstingNumbers = ["primes" : [2,3,5,5,11,13],
"trianguler" : [1,3,4,56,6]]
for key in interstingNumbers.keys {
interstingNumbers[key]?.sort(by: >)
}
print(interstingNumbers["primes"] ?? "")
- 遍歷字典 每個(gè)字典都是無(wú)序的鍵值對(duì)的集合
var imagePaths = ["star": "/glyphs/star.png",
"portrait": "/images/content/portrait.jpg",
"spacer": "/images/shared/spacer.gif"]
for (key,value) in imagePaths {
print("\(key) : \(value)")
}
- 創(chuàng)建字典
var dict : [String : String] = Dictionary.init(minimumCapacity: 10)
dict["name"] = "lili"
dict.isEmpty
dict.count
- 訪問(wèn)字典的鍵值對(duì)
imagePaths["star"]
imagePaths.index(forKey: "spacer")
imagePaths.first
imagePaths.keys
imagePaths.values
- 添加鍵值對(duì)
imagePaths.updateValue("falsh.png", forKey: "xxx")
imagePaths
- 移除鍵值對(duì)
imagePaths.removeValue(forKey: "flash")
imagePaths.removeAll()
- 遍歷字典
imagePaths.enumerated()
imagePaths.makeIterator()
imagePaths.underestimatedCount
imagePaths.first
可選項(xiàng) Optional
- 可選項(xiàng) ?
let shortForm: Int? = Int("33")
// 可選項(xiàng)包含兩個(gè)分支 Optional.some
let number: Int? = Optional.some(44)
let nonumber: Int? = Optional.none
print(nonumber == nil)
- 在很多情況下使用可選項(xiàng)都必須進(jìn)行解包
let imagePaths = ["star": "/glyphs/star.png",
"portrait": "/images/content/portrait.jpg",
"spacer": "/images/shared/spacer.gif"]```
* 解包方式一: if let
if let starPath = imagePaths["star"] {
print("The star image is at '(starPath)'")
} else {
print("Couldn't find the star image")
}```
- ?? 當(dāng)為nil時(shí)提供一個(gè)默認(rèn)值
let defaultiamgepath = "/iamges/default.png"
let heartpath = imagePaths["heart"] ?? defaultiamgepath
- ?? 可以多個(gè)一起使用
let shapePath = imagePaths["cir"] ?? imagePaths["squ"] ?? defaultiamgepath
- 強(qiáng)制解包 解包失敗會(huì)崩潰
let num = Int("42")!
let isPng = imagePaths["star"]! .hasSuffix(".png")
switch 語(yǔ)句
- 不存在隱式的貫穿,不需要在 case 分支中顯式地使用break語(yǔ)句。
- 每一個(gè) case 分支都必須包含至少一條語(yǔ)句。像下面這樣書(shū)寫(xiě)代碼是無(wú)效的,因?yàn)榈谝粋€(gè) case 分支是空的
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a": // 無(wú)效,這個(gè)分支下面沒(méi)有語(yǔ)句
case "A":
print("The letter A")
default:
print("Not the letter A")
}
// 這段代碼會(huì)報(bào)編譯錯(cuò)誤
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a", "A":
print("The letter A")
default:
print("Not the letter A")
}
// 輸出 "The letter A
- 區(qū)間匹配 case 分支的模式也可以是一個(gè)值的區(qū)間。
let approximateCount = 62
let countedThings = "moons orbiting Saturn"
var naturalCount: String
switch approximateCount {
case 0:
naturalCount = "no"
case 1..<5:
naturalCount = "a few"
case 5..<12:
naturalCount = "several"
case 12..<100:
naturalCount = "dozens of"
case 100..<1000:
naturalCount = "hundreds of"
default:
naturalCount = "many"
}
print("There are \(naturalCount) \(countedThings).")
// 輸出 "There are dozens of moons orbiting Saturn."
- case 分支的模式可以使用where語(yǔ)句來(lái)判斷額外的條件
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
print("(\(x), \(y)) is just some arbitrary point")
}
// 輸出 "(1, -1) is on the line x == -y"
- 復(fù)合匹配 當(dāng)多個(gè)條件可以使用同一種方法來(lái)處理時(shí),可以將這幾種可能放在同一個(gè)case后面,并且用逗號(hào)隔開(kāi)。當(dāng)case后面的任意一種模式匹配的時(shí)候,這條分支就會(huì)被匹配。并且,如果匹配列表過(guò)長(zhǎng),還可以分行書(shū)寫(xiě)
let someCharacter: Character = "e"
switch someCharacter {
case "a", "e", "i", "o", "u":
print("\(someCharacter) is a vowel")
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
"n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
print("\(someCharacter) is a consonant")
default:
print("\(someCharacter) is not a vowel or a consonant")
}
// 輸出 "e is a vowel"
控制轉(zhuǎn)移語(yǔ)句
- continue continue語(yǔ)句告訴一個(gè)循環(huán)體立刻停止本次循環(huán),重新開(kāi)始下次循環(huán)
- break語(yǔ)句會(huì)立刻結(jié)束整個(gè)控制流的執(zhí)行。當(dāng)你想要更早的結(jié)束一個(gè)switch代碼塊或者一個(gè)循環(huán)體時(shí),你都可以使用break語(yǔ)句
*Switch 語(yǔ)句中的 break
當(dāng)在一個(gè)switch代碼塊中使用break時(shí),會(huì)立即中斷該switch代碼塊的執(zhí)行,并且跳轉(zhuǎn)到表示switch代碼塊結(jié)束的大括號(hào)(})后的第一行代碼
- 貫穿
let integerToDescribe = 5
var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
description += " a prime number, and also"
fallthrough
default:
description += " an integer."
}
print(description)
// 輸出 "The number 5 is a prime number, and also an integer."
提前退出
- 像if語(yǔ)句一樣,guard的執(zhí)行取決于一個(gè)表達(dá)式的布爾值。我們可以使用guard語(yǔ)句來(lái)要求條件必須為真時(shí),以執(zhí)行g(shù)uard語(yǔ)句后的代碼。不同于if語(yǔ)句,一個(gè)guard語(yǔ)句總是有一個(gè)else從句,如果條件不為真則執(zhí)行else從句中的代碼
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).")
}
檢測(cè)API的可用性 最后一個(gè)參數(shù),*,是必須的,用于指定在所有其它平臺(tái)中,如果版本號(hào)高于你的設(shè)備指定的最低版本,if語(yǔ)句的代碼塊將會(huì)運(yùn)行
if #available(iOS 10, macOS 10.12, *) {
// 在 iOS 使用 iOS 10 的 API, 在 macOS 使用 macOS 10.12 的 API
} else {
// 使用先前版本的 iOS 和 macOS 的 API
}
函數(shù)
- 多個(gè)相同類(lèi)型參數(shù) (可變參數(shù)一個(gè)函數(shù)最多只能擁有一個(gè)可變參數(shù)。)
func sumof(numbers:Int...) ->Int{
var sum = 0
for num in numbers {
sum += num
}
return sum
}
sumof(numbers: 1,2,3,5)```
* swift中的默認(rèn)參數(shù)
func makeCoffee(coffeename: String = "藍(lán)山"){
print("我要喝(coffeename)咖啡")
}
makeCoffee()
makeCoffee(coffeename: "貓屎")
* 有參有返回值
func greet(name: String,day: String,number: Int) -> String{
return "Hello \(name),Today is\(day),\(number)"
}
print(greet(name: "zhangsan", day: "33", number: 23))
* 函數(shù)返回值為元組
可選元組類(lèi)型如 (Int, Int)? 與元組包含可選類(lèi)型如 (Int?, Int?) 是不同的.可選的元組類(lèi)型,整個(gè)元組是可選的,而不只是元組中的每個(gè)元素值。
func calculate(scores: [Int]) -> (max: Int,min: Int,sum: Int){
var max = scores[0]
var min = scores[0]
var sum = 0
for num in scores {
if num > max {
max = num
}else if num < min{
min = num
}
sum += num
}
return (max,min,sum)
}
let statistics = calculate(scores: [3,4,5])
print(statistics.max)
print(statistics.0)
* 輸入輸出函數(shù)
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now (someInt), and anotherInt is now (anotherInt)")
// 打印 "someInt is now 107, and anotherInt is now 3"
* 函數(shù)作為返回類(lèi)型
func makeIncrementer() -> ((Int,Int) -> Int){
func addNumber(num1: Int,num2: Int) -> Int{
return num1 + num2
}
return addNumber
}
let add = makeIncrementer()
add(3,4)
* **函數(shù)作為參數(shù)(重點(diǎn))**
* 平方
func square(a: Float) -> Float{
return a * a
}
square(a: 2.0)```
- 立方
func cube(a: Float) -> Float{
return a * a * a
}
cube(a: 2.0)```
* 平均值
func averageSumm(num1: Float,num2: Float,function:(Float -> Float)) -> Float{
return (function(num1) + function(num2))/2
}```
- 函數(shù)的嵌套使用
func test(){
func demo(){}
demo()
}
test()
- 排序
var numbers = [1,3,2,5,63,7,0]
let sortNmbers = numbers.sorted(){
$0 < $1
}
print(sortNmbers)
類(lèi)
class Strudent : NSObject{
// 定義存儲(chǔ)屬性
var name: String?
var age: Int = 0
var mathScore: Double = 0
var chineseScore: Double = 0
// 定義計(jì)算型屬性:通過(guò)別的方式計(jì)算得到結(jié)果的屬性
var averageScore: Double{
// 在swift中如果使用當(dāng)前對(duì)象的屬性和方法不需要添加self
return (mathScore + chineseScore) * 0.5
}
// 定義類(lèi)屬性: 類(lèi)屬性是和整個(gè)類(lèi)相關(guān)的屬性,而且是通過(guò)類(lèi)名來(lái)進(jìn)行訪問(wèn)
static var courseCount: Int = 0
}
// 給類(lèi)屬性賦值
Strudent.courseCount = 2
let stu = Strudent()
//stu.age = 20
stu.name = "zhangsan"
stu.mathScore = 50
stu.chineseScore = 60
stu.averageScore
// 解包
if let name = stu.name {
print(name)
}
// 可以利用KVC賦值
stu.setValue("lisi", forKey: "name")
- 監(jiān)聽(tīng)屬性變化
class Person: NSObject{
// var name: String?
var name: String?{
// 監(jiān)聽(tīng)屬性的變化
willSet {// 屬性即將改變時(shí)進(jìn)行監(jiān)聽(tīng)
print("willsetlllll")
}
didSet {//屬性已經(jīng)改變時(shí)進(jìn)行監(jiān)聽(tīng)
print("didsettttt")
}
}
// 在構(gòu)造函數(shù)中,如果沒(méi)有明確super.init(),那么系統(tǒng)會(huì)幫助調(diào)用super.init()
override init() {
super.init()
print("=====")
}
// 自定義構(gòu)造函數(shù)
init(name: String) {
self.name = name
}
// 字典轉(zhuǎn)模型
init(dict: [String: AnyObject]) {
super.init()
setValuesForKeys(dict)
}
override func setValue(_ value: Any?, forUndefinedKey key: String) {
}
}
//let p1 = Person.init()
//let p2 = Person.init(name: "lisi")
let p3 = Person.init(dict: ["name": "wangwu" as AnyObject,
"age": 24 as AnyObject
])
print(p3.name ?? "")
便利構(gòu)造函數(shù)
1.遍歷構(gòu)造函數(shù)通常都是寫(xiě)在extension里面
2.遍歷構(gòu)造函數(shù)init前面需要加載convenience
3.在遍歷構(gòu)造函數(shù)中需要明確的調(diào)用self.init()
extension UIButton {
convenience init(imageName: String,backGroundName: String) {
self.init()
setImage(UIImage.init(named:imageName), for:UIControlState())
setImage(UIImage.init(named: imageName + "_highlighted"), for: .highlighted)
setBackgroundImage(UIImage.init(named: backGroundName), for: .normal)
setBackgroundImage(UIImage.init(named: backGroundName + "highlighted"), for: .highlighted)
sizeToFit()
}
}
重寫(xiě)一個(gè)類(lèi)的description屬性
// MARK:- 重寫(xiě)description
override var description: String{
return dictionaryWithValues(forKeys: ["access_token", "expires_in", "uid"]).description
}
點(diǎn)擊事件需要添加@objc fileprivate 非對(duì)外方法添加fileprivate
GCD 的使用
- 調(diào)度組:
let group = DispatchGroup.init()
// 入組
group.enter()
// 出租
group.leave()
// 通知
group.notify(queue: DispatchQueue.main) {
// 執(zhí)行code
}
- 延遲執(zhí)行
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 5) {
// 執(zhí)行code
}
let queue = DispatchQueue.init(label: "")
queue.async {
<#code#>
}
隊(duì)列相關(guān)
// 創(chuàng)建隊(duì)列
let queue = DispatchQueue(label: "com.appcoda.myqueue")
// 指定優(yōu)先級(jí)
let queue1 = DispatchQueue.init(label: "com.appcoda.myqueue1", qos:.background)
// 創(chuàng)建一個(gè)并發(fā)隊(duì)列
let queue1 = DispatchQueue.init(label: "com.appcoda.myqueue1",attributes:.concurrent)
//并發(fā)執(zhí)行
queue1.async {
for i in 100 ..< 110{
print("??",i)
}
}
// 獲取全局隊(duì)列
DispatchQueue.global()
// 主隊(duì)列
DispatchQueue.main
workitem
// workitem
func useWorkItem() {
var value = 10
// 方法1
let workItem = DispatchWorkItem {
value += 5
}
workItem.perform()
// 方法2
let queue = DispatchQueue.global(qos: .utility)
queue.async(execute: workItem)
//通知
workItem.notify(queue: DispatchQueue.main) {
print("value = ", value)
}
}
閉包
- 閉包可以捕獲和存儲(chǔ)其所在上下文中任意常量和變量的引用。被稱(chēng)為包裹常量和變量。 Swift 會(huì)為你管理在捕獲過(guò)程中涉及到的所有內(nèi)存操作。
{ (parameters) -> returnType in
statements
}
枚舉
- 應(yīng)該以一個(gè)大寫(xiě)字母開(kāi)頭。給枚舉類(lèi)型起一個(gè)單數(shù)名字而不是復(fù)數(shù)名字
與 C 和 Objective-C 不同,Swift 的枚舉成員在被創(chuàng)建時(shí)不會(huì)被賦予一個(gè)默認(rèn)的整型值。在上面的CompassPoint例子中,north,south,east和west不會(huì)被隱式地賦值為0,1,2和3。相反,這些枚舉成員本身就是完備的值,這些值的類(lèi)型是已經(jīng)明確定義好的CompassPoint類(lèi)型。
enum CompassPoint {
case north
case south
case east
case west
}
- 多個(gè)成員值可以出現(xiàn)在同一行上,用逗號(hào)隔開(kāi):
enum Planet {
case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}
- 使用switch語(yǔ)句匹配枚舉值
directionToHead = .south
switch directionToHead {
case .north:
print("Lots of planets have a north")
case .south:
print("Watch out for penguins")
case .east:
print("Where the sun rises")
case .west:
print("Where the skies are blue")
}
// 打印 "Watch out for penguins”
判斷一個(gè)枚舉類(lèi)型的值時(shí),switch語(yǔ)句必須窮舉所有情況。如果忽略了.west這種情況,上面那段代碼將無(wú)法通過(guò)編譯,因?yàn)樗鼪](méi)有考慮到CompassPoint的全部成員。強(qiáng)制窮舉確保了枚舉成員不會(huì)被意外遺漏。
- 當(dāng)不需要匹配每個(gè)枚舉成員的時(shí)候,你可以提供一個(gè)default分支來(lái)涵蓋所有未明確處理的枚舉成員
let somePlanet = Planet.earth
switch somePlanet {
case .earth:
print("Mostly harmless")
default:
print("Not a safe place for humans")
}
// 打印 "Mostly harmless”
- 原始值的隱式賦值
- 在使用原始值為整數(shù)或者字符串類(lèi)型的枚舉時(shí),不需要顯式地為每一個(gè)枚舉成員設(shè)置原始值,Swift 將會(huì)自動(dòng)為你賦值。
例如,當(dāng)使用整數(shù)作為原始值時(shí),隱式賦值的值依次遞增1。如果第一個(gè)枚舉成員沒(méi)有設(shè)置原始值,其原始值將為0 - 當(dāng)使用字符串作為枚舉類(lèi)型的原始值時(shí),每個(gè)枚舉成員的隱式原始值為該枚舉成員的名稱(chēng)。
- 使用枚舉成員的rawValue屬性可以訪問(wèn)該枚舉成員的原始值:
let earthsOrder = Planet.earth.rawValue
// earthsOrder 值為 3
let sunsetDirection = CompassPoint.west.rawValue
// sunsetDirection 值為 "west"
- 遞歸枚舉
indirect enum ArithmeticExpression {
case number(Int)
case addition(ArithmeticExpression, ArithmeticExpression)
case multiplication(ArithmeticExpression, ArithmeticExpression)
}
類(lèi)和結(jié)構(gòu)體
- 結(jié)構(gòu)體總是通過(guò)被復(fù)制的方式在代碼中傳遞,不使用引用計(jì)數(shù)。
class SomeClass {
// 在這里定義類(lèi)
}
struct SomeStructure {
// 在這里定義結(jié)構(gòu)體
}
- 構(gòu)造器最簡(jiǎn)單形式是在結(jié)構(gòu)體或者類(lèi)型名稱(chēng)后跟隨一對(duì)空括號(hào)
- 與 Objective-C 語(yǔ)言不同的是,Swift 允許直接設(shè)置結(jié)構(gòu)體屬性的子屬性。上面的最后一個(gè)例子,就是直接設(shè)置了someVideoMode中resolution屬性的width這個(gè)子屬性,以上操作并不需要重新為整個(gè)resolution屬性設(shè)置新值。
- 結(jié)構(gòu)體類(lèi)型的成員逐一構(gòu)造器所有結(jié)構(gòu)體都有一個(gè)自動(dòng)生成的成員逐一構(gòu)造器,用于初始化新結(jié)構(gòu)體實(shí)例中成員的屬性。新實(shí)例中各個(gè)屬性的初始值可以通過(guò)屬性的名稱(chēng)傳遞到成員逐一構(gòu)造器之中
let vga = Resolution(width:640, height: 480)
- 結(jié)構(gòu)體和枚舉是值類(lèi)型
值類(lèi)型被賦予給一個(gè)變量、常量或者被傳遞給一個(gè)函數(shù)的時(shí)候,其值會(huì)被拷貝。 - 恒等運(yùn)算符
- 因?yàn)轭?lèi)是引用類(lèi)型,有可能有多個(gè)常量和變量在幕后同時(shí)引用同一個(gè)類(lèi)實(shí)例。(對(duì)于結(jié)構(gòu)體和枚舉來(lái)說(shuō),這并不成立。因?yàn)樗鼈冏鳛橹殿?lèi)型,在被賦予到常量、變量或者傳遞到函數(shù)時(shí),其值總是會(huì)被拷貝。)
- 等價(jià)于(===)
不等價(jià)于(!==)
- 字符串、數(shù)組、和字典類(lèi)型的賦值與復(fù)制行為
- Swift 中,許多基本類(lèi)型,諸如String,Array和Dictionary類(lèi)型均以結(jié)構(gòu)體的形式實(shí)現(xiàn)。這意味著被賦值給新的常量或變量,或者被傳入函數(shù)或方法中時(shí),它們的值會(huì)被拷貝。Objective-C 中NSString,NSArray和NSDictionary類(lèi)型均以類(lèi)的形式實(shí)現(xiàn),而并非結(jié)構(gòu)體。它們?cè)诒毁x值或者被傳入函數(shù)或方法時(shí),不會(huì)發(fā)生值拷貝,而是傳遞現(xiàn)有實(shí)例的引用。
屬性
- 存儲(chǔ)屬性只能用于類(lèi)和結(jié)構(gòu)體,計(jì)算屬性可以用于類(lèi)結(jié)構(gòu)體和枚舉.
- 如果創(chuàng)建了一個(gè)結(jié)構(gòu)體的實(shí)例并將其賦值給一個(gè)常量,則無(wú)法修改該實(shí)例的任何屬性,即使有屬性被聲明為變量也不行:
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
// 該區(qū)間表示整數(shù)0,1,2,3
rangeOfFourItems.firstValue = 6
// 盡管 firstValue 是個(gè)變量屬性,這里還是會(huì)報(bào)錯(cuò)
這種行為是由于結(jié)構(gòu)體(struct)屬于值類(lèi)型。當(dāng)值類(lèi)型的實(shí)例被聲明為常量的時(shí)候,它的所有屬性也就成了常量。
屬于引用類(lèi)型的類(lèi)(class)則不一樣。把一個(gè)引用類(lèi)型的實(shí)例賦給一個(gè)常量后,仍然可以修改該實(shí)例的變量屬性
- 懶加載屬性lazy
必須將延遲存儲(chǔ)屬性聲明成變量(使用 var 關(guān)鍵字),因?yàn)閷傩缘某跏贾悼赡茉趯?shí)例構(gòu)造完成之后才會(huì)得到。而常量屬性在構(gòu)造過(guò)程完成之前必須要有初始值,因此無(wú)法聲明成延遲屬性。注意
如果一個(gè)被標(biāo)記為 lazy 的屬性在沒(méi)有初始化時(shí)就同時(shí)被多個(gè)線程訪問(wèn),則無(wú)法保證該屬性只會(huì)被初始化一次。
- 計(jì)算型屬性:
struct AlternativeRect {
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set {
origin.x = newValue.x - (size.width / 2)
origin.y = newValue.y - (size.height / 2)
}
}
}
- 只讀計(jì)算屬性只有 getter 沒(méi)有 setter 的計(jì)算屬性就是只讀計(jì)算屬性。只讀計(jì)算屬性總是返回一個(gè)值,可以通過(guò)點(diǎn)運(yùn)算符訪問(wèn),但不能設(shè)置新的值
注意
必須使用 var 關(guān)鍵字定義計(jì)算屬性,包括只讀計(jì)算屬性,因?yàn)樗鼈兊闹挡皇枪潭ǖ摹et 關(guān)鍵字只用來(lái)聲明常量屬性,表示初始化后再也無(wú)法修改的值
- 只讀計(jì)算屬性的聲明可以去掉 get 關(guān)鍵字和花括號(hào):
struct Cuboid {
var width = 0.0, height = 0.0, depth = 0.0
var volume: Double {
return width * height * depth
}
}
let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
// 打印 "the volume of fourByFiveByTwo is 40.0"
- 屬性觀察器
class StepCounter {
var totalSteps: Int = 0 {
willSet(newTotalSteps) {
print("About to set totalSteps to \(newTotalSteps)")
}
didSet {
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
// About to set totalSteps to 200
// Added 200 steps
stepCounter.totalSteps = 360
// About to set totalSteps to 360
// Added 160 steps
stepCounter.totalSteps = 896
// About to set totalSteps to 896
// Added 536 steps
全局變量和局部變量
- 全局變量是在函數(shù)、方法、閉包或任何類(lèi)型之外定義的變量。局部變量是在函數(shù)、方法或閉包內(nèi)部定義的變量。
注意全局的常量或變量都是延遲計(jì)算的,跟[延遲存儲(chǔ)屬性]相似,不同的地方在于,全局的常量或變量不需要標(biāo)記lazy
修飾符。局部范圍的常量或變量從不延遲計(jì)算。
方法
- 類(lèi)、結(jié)構(gòu)體、枚舉都可以定義實(shí)例方法;類(lèi)、結(jié)構(gòu)體、枚舉也可以定義類(lèi)型方法
結(jié)構(gòu)體和枚舉能夠定義方法是 Swift 與 C/Objective-C 的主要區(qū)別之一。
實(shí)際上,你不必在你的代碼里面經(jīng)常寫(xiě)self。不論何時(shí),只要在一個(gè)方法中使用一個(gè)已知的屬性或者方法名稱(chēng),如果你沒(méi)有明確地寫(xiě)self,Swift 假定你是指當(dāng)前實(shí)例的屬性或者方法。
在實(shí)例方法中修改值類(lèi)型
結(jié)構(gòu)體和枚舉是值類(lèi)型。默認(rèn)情況下,值類(lèi)型的屬性不能在它的實(shí)例方法中被修改。
但是,如果你確實(shí)需要在某個(gè)特定的方法中修改結(jié)構(gòu)體或者枚舉的屬性,你可以為這個(gè)方法選擇可變(mutating)行為,然后就可以從其方法內(nèi)部改變它的屬性;并且這個(gè)方法做的任何改變都會(huì)在方法執(zhí)行結(jié)束時(shí)寫(xiě)回到原始結(jié)構(gòu)中。方法還可以給它隱含的self屬性賦予一個(gè)全新的實(shí)例,這個(gè)新實(shí)例在方法結(jié)束時(shí)會(huì)替換現(xiàn)存實(shí)例。
要使用可變方法,將關(guān)鍵字mutating 放到方法的func關(guān)鍵字之前就可以了
struct Point {
var x = 0.0, y = 0.0
mutating func moveByX(deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
}
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveByX(2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))")
// 打印 "The point is now at (3.0, 4.0)"
注意,不能在結(jié)構(gòu)體類(lèi)型的常量(a constant of structure type)上調(diào)用可變方法,因?yàn)槠鋵傩圆荒鼙桓淖儯词箤傩允亲兞繉傩裕?/p>
let fixedPoint = Point(x: 3.0, y: 3.0)fixedPoint.moveByX(2.0, y: 3.0)// 這里將會(huì)報(bào)告一個(gè)錯(cuò)誤
- 在可變方法中給 self 賦值
可變方法能夠賦給隱含屬性self一個(gè)全新的實(shí)例
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
self = Point(x: x + deltaX, y: y + deltaY)
}
}
類(lèi)型方法
- 方法的func關(guān)鍵字之前加上關(guān)鍵字static,來(lái)指定類(lèi)型方法。類(lèi)還可以用關(guān)鍵字class來(lái)允許子類(lèi)重寫(xiě)父類(lèi)的方法實(shí)現(xiàn)。
注意
在 Objective-C 中,你只能為 Objective-C 的類(lèi)類(lèi)型(classes)定義類(lèi)型方法(type-level methods)。在 Swift 中,你可以為所有的類(lèi)、結(jié)構(gòu)體和枚舉定義類(lèi)型方法。每一個(gè)類(lèi)型方法都被它所支持的類(lèi)型顯式包含
下標(biāo)
Swift 的Dictionary類(lèi)型的下標(biāo)接受并返回可選類(lèi)型的值。上例中的numberOfLegs字典通過(guò)下標(biāo)返回的是一個(gè)Int?或者說(shuō)“可選的int”。Dictionary類(lèi)型之所以如此實(shí)現(xiàn)下標(biāo),是因?yàn)椴皇敲總€(gè)鍵都有個(gè)對(duì)應(yīng)的值,同時(shí)這也提供了一種通過(guò)鍵刪除對(duì)應(yīng)值的方式,只需將鍵對(duì)應(yīng)的值賦值為nil即可。
繼承
- 在 Swift 中,繼承是區(qū)分「類(lèi)」與其它類(lèi)型的一個(gè)基本特征。
- 可以為類(lèi)中繼承來(lái)的屬性添加屬性觀察器,這樣一來(lái),當(dāng)屬性值改變時(shí),類(lèi)就會(huì)被通知到。可以為任何屬性添加屬性觀察器,無(wú)論它原本被定義為存儲(chǔ)型屬性還是計(jì)算型屬性
- 子類(lèi)
class SomeClass: SomeSuperclass {
// 這里是子類(lèi)的定義
}
重寫(xiě)
- 如果要重寫(xiě)某個(gè)特性,你需要在重寫(xiě)定義的前面加上override關(guān)鍵字。這么做,你就表明了你是想提供一個(gè)重寫(xiě)版本,而非錯(cuò)誤地提供了一個(gè)相同的定義。意外的重寫(xiě)行為可能會(huì)導(dǎo)致不可預(yù)知的錯(cuò)誤,任何缺少override關(guān)鍵字的重寫(xiě)都會(huì)在編譯時(shí)被診斷為錯(cuò)誤。
在方法someMethod()的重寫(xiě)實(shí)現(xiàn)中,可以通過(guò)super.someMethod()來(lái)調(diào)用超類(lèi)版本的someMethod()方法。
在屬性someProperty的 getter 或 setter 的重寫(xiě)實(shí)現(xiàn)中,可以通過(guò)super.someProperty來(lái)訪問(wèn)超類(lèi)版本的someProperty屬性。
在下標(biāo)的重寫(xiě)實(shí)現(xiàn)中,可以通過(guò)super[someIndex]來(lái)訪問(wèn)超類(lèi)版本中的相同下標(biāo)。
注意
你不可以為繼承來(lái)的常量存儲(chǔ)型屬性或繼承來(lái)的只讀計(jì)算型屬性添加屬性觀察器。這些屬性的值是不可以被設(shè)置的,所以,為它們提供willSet或didSet實(shí)現(xiàn)是不恰當(dāng)。
此外還要注意,你不可以同時(shí)提供重寫(xiě)的 setter 和重寫(xiě)的屬性觀察器。如果你想觀察屬性值的變化,并且你已經(jīng)為那個(gè)屬性提供了定制的 setter,那么你在 setter 中就可以觀察到任何值變化了。
防止重寫(xiě)
- 你可以通過(guò)把方法,屬性或下標(biāo)標(biāo)記為final來(lái)防止它們被重寫(xiě),只需要在聲明關(guān)鍵字前加上final修飾符即可(例如:final var,final func,final class func,以及final subscript)。
構(gòu)造過(guò)程
構(gòu)造過(guò)程是使用類(lèi)、結(jié)構(gòu)體或枚舉類(lèi)型的實(shí)例之前的準(zhǔn)備過(guò)程。在新實(shí)例可用前必須執(zhí)行這個(gè)過(guò)程,具體操作包括設(shè)置實(shí)例中每個(gè)存儲(chǔ)型屬性的初始值和執(zhí)行其他必須的設(shè)置或初始化工作。
類(lèi)和結(jié)構(gòu)體在創(chuàng)建實(shí)例時(shí),必須為所有存儲(chǔ)型屬性設(shè)置合適的初始值。存儲(chǔ)型屬性的值不能處于一個(gè)未知的狀態(tài)。
你可以在構(gòu)造器中為存儲(chǔ)型屬性賦初值,也可以在定義屬性時(shí)為其設(shè)置默認(rèn)值。
注意
當(dāng)你為存儲(chǔ)型屬性設(shè)置默認(rèn)值或者在構(gòu)造器中為其賦值時(shí),它們的值是被直接設(shè)置的,不會(huì)觸發(fā)任何屬性觀察者。
- 不帶外部名的構(gòu)造器參數(shù)如果你不希望為構(gòu)造器的某個(gè)參數(shù)提供外部名字,你可以使用下劃線(_)來(lái)顯式描述它的外部名,以此重寫(xiě)上面所說(shuō)的默認(rèn)行為
*構(gòu)造過(guò)程中常量屬性的修改 你可以在構(gòu)造過(guò)程中的任意時(shí)間點(diǎn)給常量屬性指定一個(gè)值,只要在構(gòu)造過(guò)程結(jié)束時(shí)是一個(gè)確定的值。一旦常量屬性被賦值,它將永遠(yuǎn)不可更改。
注意
對(duì)于類(lèi)的實(shí)例來(lái)說(shuō),它的常量屬性只能在定義它的類(lèi)的構(gòu)造過(guò)程中修改;不能在子類(lèi)中修改。
- 默認(rèn)構(gòu)造器 ()
- 結(jié)構(gòu)體的逐一成員構(gòu)造器 如果結(jié)構(gòu)體沒(méi)有提供自定義的構(gòu)造器,它們將自動(dòng)獲得一個(gè)逐一成員構(gòu)造器,即使結(jié)構(gòu)體的存儲(chǔ)型屬性沒(méi)有默認(rèn)值。
struct Size {
var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)
類(lèi)的繼承和構(gòu)造過(guò)程
- 類(lèi)里面的所有存儲(chǔ)型屬性——包括所有繼承自父類(lèi)的屬性——都必須在構(gòu)造過(guò)程中設(shè)置初始值。
- 構(gòu)造器的繼承和重寫(xiě)跟 Objective-C 中的子類(lèi)不同,Swift 中的子類(lèi)默認(rèn)情況下不會(huì)繼承父類(lèi)的構(gòu)造器。Swift 的這種機(jī)制可以防止一個(gè)父類(lèi)的簡(jiǎn)單構(gòu)造器被一個(gè)更精細(xì)的子類(lèi)繼承,并被錯(cuò)誤地用來(lái)創(chuàng)建子類(lèi)的實(shí)例。
注意
子類(lèi)可以在初始化時(shí)修改繼承來(lái)的變量屬性,但是不能修改繼承來(lái)的常量屬性。
?### 析構(gòu) deinit
- 在類(lèi)的定義中,每個(gè)類(lèi)最多只能有一個(gè)析構(gòu)器,而且析構(gòu)器不帶任何參數(shù)
deinit {
// 執(zhí)行析構(gòu)過(guò)程
}
擴(kuò)展
- 添加計(jì)算型屬性和計(jì)算型類(lèi)型屬性
- 定義實(shí)例方法和類(lèi)型方法
- 提供新的構(gòu)造器
- 定義下標(biāo)
- 定義和使用新的嵌套類(lèi)型
- 使一個(gè)已有類(lèi)型符合某個(gè)協(xié)議
extension SomeType {
// 為 SomeType 添加的新功能寫(xiě)到這里
}
extension SomeType: SomeProtocol, AnotherProctocol {
// 協(xié)議實(shí)現(xiàn)寫(xiě)到這里
}
注意
擴(kuò)展可以添加新的計(jì)算型屬性,但是不可以添加存儲(chǔ)型屬性,也不可以為已有屬性添加屬性觀察器。
閉包
- 閉包表達(dá)式語(yǔ)法
{ (parameters) -> returnType in
statements
}
- 閉包的函數(shù)體部分由關(guān)鍵字in引入.該關(guān)鍵字表示閉包的參數(shù)和返回值類(lèi)型定義已經(jīng)完成,閉包函數(shù)體即將開(kāi)始.
- 單表達(dá)式閉包隱式返回單行表達(dá)式閉包可以通過(guò)省略 return 關(guān)鍵字來(lái)隱式返回單行表達(dá)式的結(jié)果
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
- 尾隨閉包
func someFunctionThatTakesAClosure(closure: () -> Void) {
// 函數(shù)體部分
}
// 以下是不使用尾隨閉包進(jìn)行函數(shù)調(diào)用
someFunctionThatTakesAClosure(closure: {
// 閉包主體部分
})
// 以下是使用尾隨閉包進(jìn)行函數(shù)調(diào)用
someFunctionThatTakesAClosure() {
// 閉包主體部分
}
- 值捕獲閉包可以在其被定義的上下文中捕獲常量或變量。即使定義這些常量和變量的原作用域已經(jīng)不存在,閉包仍然可以在閉包函數(shù)體內(nèi)引用和修改這些值。
- 閉包是引用類(lèi)型無(wú)論你將函數(shù)或閉包賦值給一個(gè)常量還是變量,你實(shí)際上都是將常量或變量的值設(shè)置為對(duì)應(yīng)函數(shù)或閉包的引用
- 逃逸閉包:當(dāng)一個(gè)閉包作為參數(shù)傳到一個(gè)函數(shù)中,但是這個(gè)閉包在函數(shù)返回之后才被執(zhí)行,我們稱(chēng)該閉包從函數(shù)中逃逸。當(dāng)你定義接受閉包作為參數(shù)的函數(shù)時(shí),你可以在參數(shù)名之前標(biāo)注 @escaping,用來(lái)指明這個(gè)閉包是允許“逃逸”出這個(gè)函數(shù)的。
- 逃逸閉包中需要顯式的引用self
- 在非逃逸閉包中可以隱式的引用self