Swift是一門開源的編程語言购桑,蘋果于2014WWDC發(fā)布伤疙,用于開發(fā)iOS豆励、OS X和watchOS應(yīng)用程序
注釋
// 這是單行注釋
/* 這是多行注釋 */
/* 這是第一個多行注釋的開頭
/* Swift的多行注釋可以嵌套在別的多行注釋之中 */
這是第一個多行注釋的結(jié)尾 */
分號
Swift不要求每行語句的結(jié)尾使用分號(;)蔫仙,也可以使用;但當(dāng)在同一行書寫多條語句時觅玻,需要分號分隔(;)
var str = "Hello World"; print(str)
標(biāo)識符
如果一定要使用關(guān)鍵字作為標(biāo)識符站辉,可以在關(guān)鍵字前后添加重音符(`)
let `class` = "try"
Swift空格
運(yùn)算符不能直接跟在變量或常量后面
let a= 1 + 2
=> 報錯
let a = 1+ 2
==> 報錯
let a = 1 + 2 => 推薦
let a = 1+2 => 也可,不報錯
打印輸出
Swift使用print函數(shù)打印輸出
print("Hello World")
完整:
/// - Parameters:
/// - items: Zero or more items to print.
/// - separator: A string to print between each item. The default is a single
/// space (`" "`).
/// - terminator: The string to print after all items have been printed. The
/// default is a newline (`"\n"`).
public func print(_ items: Any..., separator: String = " ", terminator: String = "\n")
print函數(shù)是一個全局函數(shù)
for n in 0...10{
print("\(n)", terminator: "")
}
=> 012345678910
接收用戶的輸入: readLine()函數(shù)
let input = readLine()
數(shù)據(jù)類型
編程語言 -> 使用各種數(shù)據(jù)類型來存儲不同信息
所有變量都具有數(shù)據(jù)類型兑巾,以決定能夠存儲哪種數(shù)據(jù)条获。
Int: 整型
UInt: 無符號整型
盡量使用Int,統(tǒng)一使用Int可以提高代碼的可復(fù)用性蒋歌,避免不同類型數(shù)字之間的轉(zhuǎn)換帅掘,并且匹配數(shù)字的類型推斷。
浮點(diǎn)數(shù): Float奋姿、Double
布爾值: true锄开、false素标,Swift的布爾值僅有兩個值true或false称诗,而OC則是非真則是假
字符串: String,字符串是字符的序列集合
字符: Character头遭,字符指的是單個字母
可選類型: Optional寓免,使用可選類型來處理值可能缺失的情況〖莆可選類型表示有值或沒有值袜香。
類型別名
類型別名對當(dāng)前的類型定義了另一個名字,類型別名通過使用 typealias 關(guān)鍵字來定義
typealias newname = type
=>
typealias Feet = Int
let ten: Feet = 10
print(ten)
類型安全
Swift是一個類型安全的語言鲫惶,會在編譯時進(jìn)行類型檢查蜈首,并把不匹配的類型標(biāo)記為錯誤
類型推斷
如果沒有顯式指定類型,Swift會使用類型推斷來選擇合適的類型
當(dāng)推斷浮點(diǎn)數(shù)的類型時欠母,Swift 總是會選擇Double而不是Float欢策。
變量聲明
變量聲明意思是告訴編譯器在內(nèi)存中的哪個位置上為變量創(chuàng)建多大的存儲空間。
使用var關(guān)鍵字聲明
var varA = 2
var varB: Int
varB = 3
變量命名
變量名可以由字母赏淌,數(shù)字和下劃線組成拆吆。
變量名需要以字母或下劃線開始里伯。
Swift 是一個區(qū)分大小寫的語言,所以字母大寫與小寫是不一樣的
var 你好 = "Hello"
print(你好)
變量輸出
可以使用print函數(shù)來輸出
在字符串中可以使用括號與反斜線來插入變量
var name = "百度"
var url = "https://www.baidu.com"
print("\(name)的地址為\(url)")
=> 百度的地址為https://www.baidu.com
Swift可選類型
Swift的可選類型,用于處理值缺失的情況伟葫。可選表示"那兒有一個值隙姿,并且它等于x"或者"那兒沒有值"
Swift語言定義后綴?作為命名類型Optional的簡寫
var optionalA: Int?
var optionalB: Optional<Int>
optionalA = 10
optionalB = 20
print(optionalA ?? 0)
print(optionalB ?? 0)
Optional 是一個含有兩種情況的枚舉户敬,None 和 Some(T),用來表示可能有或可能沒有值
當(dāng)聲明一個可選類型的時候想帅,要確保用括號給 ? 操作符一個合適的范圍
當(dāng)你聲明一個可選變量或者可選屬性的時候沒有提供初始值场靴,它的值會默認(rèn)為 nil
如果一個可選類型的實(shí)例包含一個值,你可以用后綴操作符 博脑!來訪問這個值
使用操作符憎乙!去獲取值為nil的可選變量會有運(yùn)行時錯誤
可選類型類似于Objective-C中指針的nil值票罐,但是nil只對類(class)有用,而可選類型對所有的類型都可用泞边,并且更安全
強(qiáng)制解析
確定可選類型確實(shí)包含值之后该押,你可以在可選的名字后面加一個感嘆號(!)來獲取值。這個感嘆號表示"我知道這個可選有值阵谚,請使用它蚕礼。"這被稱為可選值的強(qiáng)制解析
使用!來獲取一個不存在的可選值會導(dǎo)致運(yùn)行時錯誤。使用!來強(qiáng)制解析值之前梢什,一定要確定可選包含一個非nil的值
可選綁定
使用可選綁定(optional binding)來判斷可選類型是否包含值奠蹬,如果包含就把值賦給一個臨時常量或者變量∥宋纾可選綁定可以用在if和while語句中來對可選類型的值進(jìn)行判斷并把值賦給一個常量或者變量
var myString:String?
myString = "Hello Swift"
if let str = myString {
print(str)
} else {
print("字符串沒有值")
}
Swift常量
常量一旦設(shè)定囤躁,在程序運(yùn)行時就無法改變其值。
常量可以是任何的數(shù)據(jù)類型如:整型常量荔睹,浮點(diǎn)型常量狸演,字符常量或字符串常量。同樣也有枚舉類型的常量:
常量類似于變量僻他,區(qū)別在于常量的值一旦設(shè)定就不能改變宵距,而變量的值可以隨意更改
使用關(guān)鍵字let聲明
類型標(biāo)注
聲明常量或者變量的時候可以加上類型標(biāo)注(type annotation),說明常量或者變量中要存儲的值的類型
在常量或者變量名后面加上一個冒號和空格吨拗,然后加上類型名稱满哪。
var constA: Int = 10
let constB: Float = 20
PS: 常量定義時必須給初始值
布爾型字面量有三個值: true、false劝篷、nil哨鸭,它們是Swift的保留關(guān)鍵字
- true 表示真
- false 表示假
- nil 表示沒有值
Swift3取消了++和--
區(qū)間運(yùn)算符
Swift提供了兩個區(qū)間運(yùn)算符:
- 閉區(qū)間運(yùn)算符: 1...5 => 1、2携龟、3兔跌、4、5
- 開區(qū)間運(yùn)算符: 1..<5 => 1峡蟋、2坟桅、3、4
for idx in 1...5 {
print(idx)
}
=> 1
2
3
4
5
for idx in 6..<10 {
print(idx)
}
=> 6
7
8
9
合并空值運(yùn)算符??
- 合并空值運(yùn)算符a ?? b蕊蝗,如果可選項(xiàng)a有值則展開仅乓,如果沒有值,是nil蓬戚,則返回默認(rèn)值b
- 表達(dá)式a必須是一個可選類型夸楣,表達(dá)式b必須與a的存儲類型相同
- 合并空值運(yùn)算符,實(shí)際上是三元運(yùn)算符作用到 Optional 上的縮寫 a != nil ? a! : b
for循環(huán)在Swift3中被棄用
循環(huán)控制語句:
- continue語句: 告訴一個循環(huán)體立刻停止本次循環(huán)迭代,重新開始下次循環(huán)迭代豫喧。
- break語句: 中斷當(dāng)前循環(huán)石洗。
- fallthrough: 如果在一個case執(zhí)行完后,繼續(xù)執(zhí)行下面的case紧显,需要使用fallthrough(貫穿)關(guān)鍵字
// 使用字符串字面量
var str1 = "Hello World"
// String實(shí)例化
var str2 = String("Hello Swift")
print("\(str1), \(str2)")
=> Hello World, Hello Swift
var emptyStr1 = ""
var emptyStr2 = String()
if emptyStr1.isEmpty {
print("空字符串")
}
if emptyStr2.isEmpty {
print("空字符串")
}
// 字符串中插入值 => 構(gòu)建新字符串的一種方式
var insertStr = "\(str1) -> \(str2)"
print(insertStr)
可以通過+連接字符串
var str1 = "Hello"
var str2 = "World"
var string = str1 + str2
字符串長度: str.count
字符串比較: 實(shí)用==比較兩個字符串是否相等
hasPrefix(prefix: String): 檢查字符串是否擁有特定前綴
hasSuffix(suffix: String): 檢查字符串是否擁有特定后綴讲衫。
let result1 = str1.hasPrefix("H")
let result2 = str1.hasSuffix("t")
print(result1) true
print(result2) false
字符串分割為數(shù)組:
var str = "Hello World"
var array = str.split(separator: " ")
print(array.first!)
print(array[1])
=>
Hello
World
字符串操作
// 截取前n個字符
let res1 = str.prefix(5) // Hello
// 截取后n個字符
let res2 = str.suffix(5) // World
// 截取指定范圍內(nèi)字符
let range = str.index(str.startIndex, offsetBy: 7)..<str.endIndex
let res3 = str[range] // orld
// 截取從某個位置到末尾的字符
let index = str.index(str.startIndex, offsetBy: 6)
let res4 = str[index...] // World
// 從最后一個指定.字符開始截取,到字符串結(jié)束
let url = "https://www.baidu.com/image/xx/test.png"
if let dotIndex = url.lastIndex(of: ".") {
let index = url.index(dotIndex, offsetBy: 1)
let subStr = url[index..<url.endIndex]
print(subStr) // png
}
字符
Swift 的字符是一個單一的字符字符串字面量孵班,數(shù)據(jù)類型為 Character涉兽。
let ch1: Character = "A"
print(ch1)
Swift 中不能創(chuàng)建空的 Character(字符) 類型變量或常量
創(chuàng)建一個數(shù)組,并賦值給一個變量篙程,則創(chuàng)建的集合就是可以修改的枷畏。這意味著在創(chuàng)建數(shù)組后,可以通過添加虱饿、刪除拥诡、修改的方式改變數(shù)組里的項(xiàng)目。
如果將一個數(shù)組賦值給常量郭厌,數(shù)組就不可更改袋倔,并且數(shù)組的大小和內(nèi)容都不可以修改
創(chuàng)建數(shù)組推薦:
// 創(chuàng)建數(shù)組
let arr: [String] = []
let array: [String: Int] = [:]
Swift字典
Swift 字典用來存儲無序的相同類型數(shù)據(jù)的集合,Swift 字典會強(qiáng)制檢測元素的類型折柠,如果類型不同則會報錯。
Swift 字典每個值(value)都關(guān)聯(lián)唯一的鍵(key)批狐,鍵作為字典中的這個值數(shù)據(jù)的標(biāo)識符扇售。
Swift 字典的key沒有類型限制可以是整型或字符串,但必須是唯一的嚣艇。
創(chuàng)建一個字典承冰,并賦值給一個變量,則創(chuàng)建的字典就是可以修改的食零。這意味著在創(chuàng)建字典后困乒,可以通過添加、刪除贰谣、修改的方式改變字典里的項(xiàng)目娜搂。
如果將一個字典賦值給常量,字典就不可修改吱抚,并且字典的大小和內(nèi)容都不可以修改
// 創(chuàng)建字典
var dict: [Int: String] = [1: "Swift", 2: "OC", 3: "Flutter"]
print(dict) // [3: "Flutter", 1: "Swift", 2: "OC"] => 是無序的
// 訪問字典
let two = dict[2] ?? ""
print(two) // OC
// 修改字典
// 使用 updateValue(forKey:) 增加或更新字典的內(nèi)容百宇。如果 key 不存在,則添加值秘豹,如果存在則修改 key 對應(yīng)的值
let twoOld = dict.updateValue("vue", forKey: 2) ?? ""
print(twoOld) // OC
print(dict) // [3: "Flutter", 1: "Swift", 2: "vue"]
// 通過指定key修改
dict[2] = "Objective-C"
print(dict) // [1: "Swift", 3: "Flutter", 2: "Objective-C"]
// 移除key-value
// 使用 removeValueForKey() 方法來移除字典 key-value 對携御。如果 key 存在該方法返回移除的值,如果不存在返回 nil
dict.removeValue(forKey: 2)
print(dict) // [1: "Swift", 3: "Flutter"]
// 指定key的值為nil
dict[2] = "OC"
dict[2] = nil
print(dict) // [1: "Swift", 3: "Flutter"]
// 遍歷字典
// 使用 for-in 循環(huán)來遍歷某個字典中的鍵值對
for (key, value) in dict {
print("key \(key) - value \(value)")
/**
key 1 - value Swift
key 3 - value Flutter
**/
}
// 字典轉(zhuǎn)數(shù)組
let keys = dict.keys
let values = dict.values
print(keys) // [1, 3]
print(values) // ["Swift", "Flutter"]
// 使用只讀的 count 屬性來計(jì)算字典有多少個鍵值對
let count = dict.count
print(count) // 2
// 通過只讀屬性 isEmpty 來判斷字典是否為空,返回布爾值
print(dict.isEmpty) // false
Swift函數(shù)
Swift 函數(shù)用來完成特定任務(wù)的獨(dú)立的代碼塊
函數(shù)定義
Swift定義函數(shù)使用關(guān)鍵字func
定義函數(shù)的時候啄刹,可以指定一個或多個輸入?yún)?shù)和一個返回值類型
每個函數(shù)都有一個函數(shù)名來描述它的功能涮坐。通過函數(shù)名以及對應(yīng)類型的參數(shù)值來調(diào)用這個函數(shù)。函數(shù)的參數(shù)傳遞的順序必須與參數(shù)列表相同
func funcname(形參) -> returntype {
Statement1
Statement2
……
Statement N
return parameters
}
func printSelf(name: String) -> String {
return name
}
print(printSelf(name: "Hello World"))
函數(shù)參數(shù)
函數(shù)可以接受一個或者多個參數(shù)誓军,這些參數(shù)被包含在函數(shù)的括號之中膊升,以逗號分隔
func printSelf(name: String, site: String) -> String {
return name + site
}
print(printSelf(name: "百度一下:", site: "https://www.baidu.com"))
// 百度一下:https://www.baidu.com
元組作為函數(shù)返回值
元組與數(shù)組類似,不同的是谭企,元組中的元素可以是任意類型廓译,使用的是圓括號
func minMax(array: [Int]) -> (min: Int, max: Int)? {
if array.isEmpty {
return nil
}
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
if let bounds = minMax(array: [1, 5, -2, 9, 10, 20, 6]) {
print("最小值為: \(bounds.min), 最大值為: \(bounds.max)")
}
可變參數(shù)
可變參數(shù)可以接受零個或多個值。函數(shù)調(diào)用時债查,你可以用可變參數(shù)來指定函數(shù)參數(shù)非区,其數(shù)量是不確定的
可變參數(shù)通過在變量類型名后面加入(...)的方式來定義
func vari<N>(members: N...) {
for value in members {
print(value)
}
}
vari(members: 1, 3, 5, 7, 9)
Swift枚舉
枚舉簡單的說也是一種數(shù)據(jù)類型,只不過是這種數(shù)據(jù)類型只包含自定義的特定數(shù)據(jù)盹廷,它是一組有共同特性的數(shù)據(jù)的集合
Swift 中使用 enum 關(guān)鍵詞來創(chuàng)建枚舉并且把它們的整個定義放在一對大括號內(nèi)
enum enumname {
// 枚舉定義放在這里
}
enum DaysofWeek {
case Monday
case Tuesday
case Wednesday
case Thursday
case Friday
case Saturday
case Sunday
}
var weekDay = DaysofWeek.Thursday
weekDay = .Friday
switch weekDay {
case .Monday:
print("星期一")
case .Tuesday:
print("星期二")
case .Wednesday:
print("星期三")
case .Thursday:
print("星期四")
case .Friday:
print("星期五")
case .Saturday:
print("星期六")
case .Sunday:
print("星期日")
}
=> 星期五
原始值
原始值可以是字符串征绸,字符,或者任何整型值或浮點(diǎn)型值
每個原始值在它的枚舉聲明中必須是唯一的
在原始值為整數(shù)的枚舉時俄占,不需要顯式的為每一個成員賦值管怠,Swift會自動為你賦值
當(dāng)使用整數(shù)作為原始值時,隱式賦值的值依次遞增1缸榄。如果第一個值沒有被賦初值渤弛,將會被自動置為0。
enum Month: Int {
case January = 1, February, March, April, May, June, July, August, September, October, November, December
}
let month = Month.May.rawValue
print("數(shù)字月份為: \(month)")
=> 數(shù)字月份為: 5
Swift結(jié)構(gòu)體
Swift 結(jié)構(gòu)體是構(gòu)建代碼所用的一種通用且靈活的構(gòu)造體
可以為結(jié)構(gòu)體定義屬性(常量甚带、變量)和添加方法她肯,從而擴(kuò)展結(jié)構(gòu)體的功能
與 C 和 Objective C 不同的是:
- 結(jié)構(gòu)體不需要包含實(shí)現(xiàn)文件和接口
- 結(jié)構(gòu)體允許我們創(chuàng)建一個單一文件,且系統(tǒng)會自動生成面向其它代碼的外部接口
結(jié)構(gòu)體總是通過被復(fù)制的方式在代碼中傳遞鹰贵,因此它的值是不可修改的
通過struct關(guān)鍵字來定義結(jié)構(gòu)體:
struct structname {
definition1
definition2
...
definitionN
}
struct MarkStruct {
var mark1 = 99
var mark2 = 90
}
let mark = MarkStruct()
print("mark1: \(mark.mark1), mark2: \(mark.mark2)")
=> mark1: 99, mark2: 90
結(jié)構(gòu)體應(yīng)用
可以使用結(jié)構(gòu)體來定義你的自定義數(shù)據(jù)類型
結(jié)構(gòu)體實(shí)例總是通過值傳遞來定義你的自定義數(shù)據(jù)類型
按照通用的準(zhǔn)則晴氨,當(dāng)符合一條或多條以下條件時,請考慮構(gòu)建結(jié)構(gòu)體:
- 結(jié)構(gòu)體的主要目的是用來封裝少量相關(guān)簡單數(shù)據(jù)值
- 有理由預(yù)計(jì)一個結(jié)構(gòu)體實(shí)例在賦值或傳遞時碉输,封裝的數(shù)據(jù)將會被拷貝而不是被引用
- 任何在結(jié)構(gòu)體中儲存的值類型屬性籽前,也將會被拷貝,而不是被引用
- 結(jié)構(gòu)體不需要去繼承另一個已存在類型的屬性或者行為
舉例來說敷钾,以下情境中適合使用結(jié)構(gòu)體:
- 幾何形狀的大小枝哄,封裝一個width屬性和height屬性,兩者均為Double類型闰非。
- 一定范圍內(nèi)的路徑膘格,封裝一個start屬性和length屬性,兩者均為Int類型
- 三維坐標(biāo)系內(nèi)一點(diǎn)财松,封裝x瘪贱,y和z屬性纱控,三者均為Double類型
結(jié)構(gòu)體實(shí)例是通過值傳遞而不是通過引用傳遞
struct MarkStruct {
var mark1: Int
var mark2: Int
var mark3: Int
init(mark1: Int, mark2: Int, mark3: Int) {
self.mark1 = mark1
self.mark2 = mark2
self.mark3 = mark3
}
}
print("好成績:")
let mark = MarkStruct(mark1: 98, mark2: 99, mark3: 96)
print(mark.mark1)
print(mark.mark2)
print(mark.mark3)
print("壞成績:")
let fail = MarkStruct(mark1: 30, mark2: 38, mark3: 23)
print(fail.mark1)
print(fail.mark2)
print(fail.mark3)
Swift類
Swift 類是構(gòu)建代碼所用的一種通用且靈活的構(gòu)造體
可以為類定義屬性(變量和常量)和方法
Swift 并不要求你為自定義類去創(chuàng)建獨(dú)立的接口和實(shí)現(xiàn)文件。你所要做的是在一個單一文件中定義一個類菜秦,系統(tǒng)會自動生成面向其它代碼的外部接口
類和結(jié)構(gòu)體對比
Swift中類和結(jié)構(gòu)體有很多共同點(diǎn):
- 定義屬性用于存儲值
- 定義方法用于提供功能
- 定義附屬腳本用于訪問值
- 定義構(gòu)造器用于生成初始化值
- 通過擴(kuò)展以增加默認(rèn)實(shí)現(xiàn)的功能
- 符合協(xié)議以對某類提供標(biāo)準(zhǔn)功能
與結(jié)構(gòu)體相比甜害,類還有如下的附加功能:
- 繼承允許一個類繼承另一個類的特征
- 類型轉(zhuǎn)換允許在運(yùn)行時檢查和解釋一個類實(shí)例的類型
- 解構(gòu)器允許一個類實(shí)例釋放任何其所被分配的資源
- 引用計(jì)數(shù)允許對一個類的多次引用
語法:
class classname {
Definition 1
Definition 2
...
Definition N
}
類定義:
class student {
var studentName: String
var mark: Int
}
實(shí)例化:
let s = student()
恒等運(yùn)算符
因?yàn)轭愂且妙愋停锌赡苡卸鄠€常量和變量在后臺同時引用某一個類實(shí)例
為了能夠判定兩個常量或者變量是否引用同一個類實(shí)例球昨,Swift 內(nèi)建了兩個恒等運(yùn)算符
===: 如果兩個常量或者變量引用同一個類實(shí)例則返回 true
!==: 如果兩個常量或者變量引用不同一個類實(shí)例則返回 true
Swift屬性
Swift 屬性將值跟特定的類尔店、結(jié)構(gòu)或枚舉關(guān)聯(lián)
屬性可分為存儲屬性和計(jì)算屬性
存儲屬性: 存儲常量或變量作為實(shí)例的一部分,用于類和結(jié)構(gòu)體
計(jì)算屬性: 計(jì)算(而不是存儲)一個值主慰,用于類嚣州、結(jié)構(gòu)體和枚舉
簡單來說,一個存儲屬性就是存儲在特定類或結(jié)構(gòu)體的實(shí)例里的一個常量或變量
存儲屬性可以是變量存儲屬性(用關(guān)鍵字var定義)共螺,也可以是常量存儲屬性(用關(guān)鍵字let定義)
- 可以在定義存儲屬性的時候指定默認(rèn)值
- 也可以在構(gòu)造過程中設(shè)置或修改存儲屬性的值该肴,甚至修改常量存儲屬性的值
延遲存儲屬性
延遲存儲屬性是指當(dāng)?shù)谝淮伪徽{(diào)用的時候才會計(jì)算其初始值的屬性
在屬性聲明前使用 lazy 來標(biāo)示一個延遲存儲屬性
注意: 必須將延遲存儲屬性聲明成變量(使用var關(guān)鍵字),因?yàn)閷傩缘闹翟趯?shí)例構(gòu)造完成之前可能無法得到藐不。而常量屬性在構(gòu)造過程完成之前必須要有初始值匀哄,因此無法聲明成延遲屬性。
延遲存儲屬性一般用于:
- 延遲對象的創(chuàng)建(懶加載)
- 當(dāng)屬性的值依賴于其他未知類
class sample {
var no1 = 0.0, no2 = 0.0
var length = 300.0, breadth = 150.0
var middle: (Double, Double) {
get {
return (length/2, breadth/2)
}
set(axis) {
no1 = axis.0 - length/2
no2 = axis.1 - breadth/2
}
// 或
// 如果計(jì)算屬性的 setter 沒有定義表示新值的參數(shù)名雏蛮,則可以使用默認(rèn)名稱 newValue
// set {
// no1 = newValue.0 - length/2
// no2 = newValue.1 - breadth/2
// }
}
}
let sample = sample()
print(sample.middle) // (150.0, 75.0)
sample.middle = (0.0, 10.0)
print(sample.no1) // -150.0
print(sample.no2) // -65.0
只讀計(jì)算屬性
只有 getter 沒有 setter 的計(jì)算屬性就是只讀計(jì)算屬性
只讀計(jì)算屬性總是返回一個值涎嚼,可以通過點(diǎn)(.)運(yùn)算符訪問,但不能設(shè)置新的值
class film {
var name = ""
var duration = 0.0
var info: [String:String] {
return ["name": self.name, "duration": "\(self.duration)"]
}
}
let film = film()
film.name = "Swift"
film.duration = 10.0
print(film.info["name"]!) // Swift
print(film.info["duration"]!) // 10.0
注意: 必須使用var關(guān)鍵字定義計(jì)算屬性挑秉,包括只讀計(jì)算屬性法梯,因?yàn)樗鼈兊闹挡皇枪潭ǖ摹et關(guān)鍵字只用來聲明常量屬性衷模,表示初始化后再也無法修改的值鹊汛。
屬性觀察器
屬性觀察器監(jiān)控和響應(yīng)屬性值的變化,每次屬性被設(shè)置值的時候都會調(diào)用屬性觀察器阱冶,甚至新的值和現(xiàn)在的值相同的時候也不例外。
可以為除了延遲存儲屬性之外的其他存儲屬性添加屬性觀察器滥嘴,也可以通過重載屬性的方式為繼承的屬性(包括存儲屬性和計(jì)算屬性)添加屬性觀察器
注意: 不需要為無法重載的計(jì)算屬性添加屬性觀察器木蹬,因?yàn)榭梢酝ㄟ^ setter 直接監(jiān)控和響應(yīng)值的變化
可以為屬性添加如下的一個或全部觀察器:
- willSet在設(shè)置新的值之前調(diào)用
- didSet在新的值被設(shè)置之后立即調(diào)用
- willSet和didSet觀察器在屬性初始化過程中不會被調(diào)用
class didSetSample {
var count: Int = 0 {
willSet(newVal) {
print("willSet: \(newVal)")
}
didSet { // oldValue為內(nèi)部屬性 舊值
if count > oldValue {
print("didSet 變化: \(count - oldValue)")
}
}
}
}
let set = didSetSample()
set.count = 100
set.count = 800
=>
willSet: 100
didSet 變化: 100
willSet: 800
didSet 變化: 700
類型屬性
屬性也可以直接用于類型本身,這種屬性稱為類型屬性若皱。
類型屬性作為類型定義的一部分镊叁,寫在類型最外層的花括號{}內(nèi)
使用關(guān)鍵字static定義值類型的類型屬性,關(guān)鍵字class來為類定義類型屬性
Swift方法
Swift方法是與某些特定類型相關(guān)聯(lián)的函數(shù)
在Objective-C中走触,類是唯一能定義方法的類型晦譬。
在Swift中,不僅能選擇是否要定義一個類/結(jié)構(gòu)體/枚舉互广,還能靈活的在創(chuàng)建的類型(類/結(jié)構(gòu)體/枚舉)上定義方法
實(shí)例方法
在 Swift 語言中敛腌,實(shí)例方法是屬于某個特定類卧土、結(jié)構(gòu)體或者枚舉類型實(shí)例的方法
實(shí)例方法提供以下方法:
- 可以訪問和修改實(shí)例屬性
- 提供與實(shí)例目的相關(guān)的功能
實(shí)例方法要寫在它所屬的類型的前后大括號({})之間。
實(shí)例方法能夠隱式訪問它所屬類型的所有的其他實(shí)例方法和屬性像樊。
實(shí)例方法只能被它所屬的類的某個特定實(shí)例調(diào)用尤莺。
實(shí)例方法不能脫離于現(xiàn)存的實(shí)例而被調(diào)用。
class Counter {
var count = 0
func increment() {
count += 1
}
func incrementBy(amount: Int) {
count += amount
}
func reset() {
count = 0
}
}
=>
// 初始值為0
let counter = Counter()
print(counter.count) // 0
// 加1
counter.increment()
print(counter.count) // 1
// 加10
counter.incrementBy(amount: 10)
print(counter.count) // 11
// 清0
counter.reset()
print(counter.count) // 0
提供外部參數(shù)名 在內(nèi)部參數(shù)名前隔一個空格
不提供外部參數(shù)名: 使用_
class area {
var result = 0
func getArea(width w: Int, _ h: Int) {
result = w * h
print(result)
}
}
self屬性
類型的每一個實(shí)例都有一個隱含屬性叫做self生棍,self完全等同于該實(shí)例本身
可以在一個實(shí)例的實(shí)例方法中使用這個隱含的self屬性來引用當(dāng)前實(shí)例
class calcator {
let a: Int
let b: Int
let res: Int
init(a: Int, b: Int) {
self.a = a
self.b = b
res = a + b
}
func tot(c: Int) -> Int {
return res - c
}
func result() {
print("結(jié)果為:\(tot(c: 20))")
print("結(jié)果為:\(tot(c: 50))")
}
}
let cal = calcator(a: 600, b: 300)
cal.result()
=>
結(jié)果為:880
結(jié)果為:850
在實(shí)例方法中修改值類型
Swift 語言中結(jié)構(gòu)體和枚舉是值類型
一般情況下颤霎,值類型的屬性不能在它的實(shí)例方法中被修改
確實(shí)需要在某個具體的方法中修改結(jié)構(gòu)體或者枚舉的屬性,你可以選擇變異(mutating)這個方法涂滴,然后方法就可以從方法內(nèi)部改變它的屬性友酱;并且它做的任何改變在方法結(jié)束時還會保留在原始結(jié)構(gòu)中
方法還可以給它隱含的self屬性賦值一個全新的實(shí)例,這個新實(shí)例在方法結(jié)束后將替換原來的實(shí)例
struct area {
var length = 1
var breadth = 1
func area() -> Int {
return length * breadth
}
mutating func scaleBy(res: Int) {
length *= res
breadth *= res
print(length)
print(breadth)
}
}
var area = area(length: 3, breadth: 5)
area.scaleBy(res: 3)
area.scaleBy(res: 30)
area.scaleBy(res: 300)
=>
9
15
270
450
81000
135000
在可變方法中給 self 賦值
可變方法能夠賦給隱含屬性 self 一個全新的實(shí)例
struct area {
var length = 1
var breadth = 1
func area() -> Int {
return length * breadth
}
mutating func scaleBy(res: Int) {
self.length *= res
self.breadth *= res
print(length)
print(breadth)
}
}
var area = area(length: 3, breadth: 5)
area.scaleBy(res: 13)
=>
39
65
類型方法
實(shí)例方法是被類型的某個實(shí)例調(diào)用的方法柔纵,你也可以定義類型本身調(diào)用的方法缔杉,這種方法就叫做類型方法
聲明結(jié)構(gòu)體和枚舉的類型方法,在方法的func關(guān)鍵字之前加上關(guān)鍵字static
類可能會用關(guān)鍵字class來允許子類重寫父類的實(shí)現(xiàn)方法首量。
類型方法和實(shí)例方法一樣用點(diǎn)號(.)語法調(diào)用
class MathClass {
class func abs(number: Int) -> Int {
if number < 0 {
return -number
} else {
return number
}
}
}
struct MathStruct {
static func abs(number: Int) -> Int {
if number < 0 {
return -number
} else {
return number
}
}
}
let no1 = MathClass.abs(number: -35)
let no2 = MathStruct.abs(number: -5)
print(no1)
print(no2)
=>
35
5
Swift繼承
繼承我們可以理解為一個類獲取了另外一個類的方法和屬性
當(dāng)一個類繼承其它類時壮吩,繼承類叫子類,被繼承類叫超類(或父類)
在 Swift 中加缘,類可以調(diào)用和訪問超類的方法鸭叙,屬性和下標(biāo)腳本,并且可以重寫它們
也可以為類中繼承來的屬性添加屬性觀察器
沒有繼承其它類的類拣宏,稱之為基類(Base Class)
防止重寫
可以使用 final 關(guān)鍵字防止它們被重寫沈贝。
可以通過在關(guān)鍵字class前添加final特性(final class)來將整個類標(biāo)記為 final 的,這樣的類是不可被繼承的勋乾,否則會報編譯錯誤
Swift構(gòu)造過程
構(gòu)造過程是為了使用某個類宋下、結(jié)構(gòu)體或枚舉類型的實(shí)例而進(jìn)行的準(zhǔn)備過程
這個過程包含了為實(shí)例中的每個屬性設(shè)置初始值和為其執(zhí)行必要的準(zhǔn)備和初始化任務(wù)。
Swift 構(gòu)造函數(shù)使用 init() 方法辑莫。
與 Objective-C 中的構(gòu)造器不同学歧,Swift 的構(gòu)造器無需返回值,它們的主要任務(wù)是保證新實(shí)例在第一次使用前完成正確的初始化
存儲型屬性的初始賦值
類和結(jié)構(gòu)體在實(shí)例創(chuàng)建時各吨,必須為所有存儲型屬性設(shè)置合適的初始值
存儲屬性在構(gòu)造器中賦值時枝笨,它們的值是被直接設(shè)置的,不會觸發(fā)任何屬性觀測器
存儲屬性在構(gòu)造器中賦值流程:
- 創(chuàng)建初始值
- 在屬性定義中指定默認(rèn)屬性值
- 初始化實(shí)例揭蜒,并調(diào)用 init() 方法
構(gòu)造過程中修改常量屬性
只要在構(gòu)造過程結(jié)束前常量的值能確定横浑,你可以在構(gòu)造過程中的任意時間點(diǎn)修改常量屬性的值。
對某個類實(shí)例來說屉更,它的常量屬性只能在定義它的類的構(gòu)造過程中修改徙融;不能在子類中修改。
struct Rectangle {
let length: Double?
init(fromBreadth breadth: Double) {
length = breadth * 10
}
init(_ area: Double) {
length = area
}
// //Cannot assign to property: 'length' is a 'let' constant
// func changeLength(val: Double) {
// length = val
// }
}
let rec = Rectangle(180)
let rec1 = Rectangle(300)
print(rec.length)
print(rec1.length)
=>
Optional(180.0)
Optional(300.0)
默認(rèn)構(gòu)造器
默認(rèn)構(gòu)造器將簡單的創(chuàng)建一個所有屬性值都設(shè)置為默認(rèn)值的實(shí)例
class ShoppingListItem {
var name: String?
var quantity: Int = 1
var purchased = false
}
let shopping = ShoppingListItem()
print(shopping.name)
print(shopping.quantity)
print(shopping.purchased)
=>
nil
1
false
結(jié)構(gòu)體的逐一成員構(gòu)造器
如果結(jié)構(gòu)體為所有存儲型屬性提供了默認(rèn)值且自身沒有提供定制的構(gòu)造器瑰谜,它們能自動獲得一個逐一成員構(gòu)造器
在調(diào)用逐一成員構(gòu)造器時欺冀,通過與成員屬性名相同的參數(shù)名進(jìn)行傳值來完成對成員屬性的初始賦值
struct Rectangle {
var length = 10.0, breadth = 20.0
}
let rec = Rectangle(length: 100.0, breadth: 200.0)
print(rec.length)
print(rec.breadth)
=>
100.0
200.0
構(gòu)造器的繼承和重載
Swift 中的子類不會默認(rèn)繼承父類的構(gòu)造器
但是如果滿足特定條件树绩,父類構(gòu)造器是可以被自動繼承的。事實(shí)上脚猾,這意味著對于許多常見場景你不必重寫父類的構(gòu)造器葱峡,并且可以在安全的情況下以最小的代價繼承父類的構(gòu)造器。
當(dāng)你重寫一個父類指定構(gòu)造器時龙助,你需要寫override修飾符
class SuperClass {
var corners = 4
var des: String {
return "\(corners) 邊"
}
}
class SonClass: SuperClass {
override init() {
super.init()
corners = 5
}
}
let supC = SuperClass()
print(supC.des)
let sonC = SonClass()
print(sonC.des)
=>
4 邊
5 邊
結(jié)構(gòu)體的可失敗構(gòu)造器
如果一個類砰奕,結(jié)構(gòu)體或枚舉類型的對象,在構(gòu)造自身的過程中有可能失敗提鸟,則為其定義一個可失敗構(gòu)造器
可以在一個類军援,結(jié)構(gòu)體或是枚舉類型的定義中,添加一個或多個可失敗構(gòu)造器称勋。
其語法為在init關(guān)鍵字后面加添問號(init?)
struct Animal {
let species: String
init?(species: String) {
if species.isEmpty { return nil }
self.species = species
}
}
let animal = Animal(species: "老虎")
if let tiger = animal {
print(tiger.species)
}
=>
老虎
枚舉的可失敗構(gòu)造器
可以通過構(gòu)造一個帶一個或多個參數(shù)的可失敗構(gòu)造器來獲取枚舉類型中特定的枚舉成員
enum TemperatureUnit {
case Kelvin, Celsius, Fahrenheit
init?(symbol: Character) {
switch symbol {
case "K":
self = .Kelvin
case "C":
self = .Celsius
case "F":
self = .Fahrenheit
default:
return nil
}
}
}
let tem = TemperatureUnit(symbol: "F")
if tem != nil {
print("這是一個已存在的溫度單位胸哥,所以初始化成功")
}
let unknownUnit = TemperatureUnit(symbol: "X")
if unknownUnit == nil {
print("這不是一個已定義的溫度單位,所以初始化失敗")
}
=>
這是一個已存在的溫度單位赡鲜,所以初始化成功
這不是一個已定義的溫度單位空厌,所以初始化失敗
類的可失敗構(gòu)造器
值類型(如結(jié)構(gòu)體或枚舉類型)的可失敗構(gòu)造器,對何時何地觸發(fā)構(gòu)造失敗這個行為沒有任何的限制银酬。
但是嘲更,類的可失敗構(gòu)造器只能在所有的類屬性被初始化后和所有類之間的構(gòu)造器之間的代理調(diào)用發(fā)生完后觸發(fā)失敗行為
class StudDetail {
var name: String
init?(name: String) {
if name.isEmpty {
return nil
}
self.name = name
}
}
let stud1 = StudDetail(name: "Tom")
if let stud = stud1 {
print(stud.name)
}
let stud2 = StudDetail(name: "")
if let stud = stud2 {
print(stud.name)
} else {
print("構(gòu)造失敗")
}
=>
Tom
構(gòu)造失敗
覆蓋一個可失敗構(gòu)造器
1.可以用子類的可失敗構(gòu)造器覆蓋基類的可失敗構(gòu)造器
2.也可以用子類的非可失敗構(gòu)造器覆蓋一個基類的可失敗構(gòu)造器
3.可以用一個非可失敗構(gòu)造器覆蓋一個可失敗構(gòu)造器,但反過來卻行不通
4.一個非可失敗的構(gòu)造器永遠(yuǎn)也不能代理調(diào)用一個可失敗構(gòu)造器
可失敗構(gòu)造器 init!
通常來說我們通過在init關(guān)鍵字后添加問號的方式(init?)來定義一個可失敗構(gòu)造器揩瞪,但你也可以使用通過在init后面添加驚嘆號的方式來定義一個可失敗構(gòu)造器(init!)
struct StudRecord {
let sName: String
init!(sName: String) {
if sName.isEmpty {
return nil
}
self.sName = sName
}
}
let stud = StudRecord(sName: "Tom")
if let stu = stud {
print("\(stu.sName)")
}
let nullStud = StudRecord(sName: "")
if nullStud == nil {
print("學(xué)生名字為空")
}
=>
Tom
學(xué)生名字為空
Swift的初始化需要保證類型的所有屬性都被初始化赋朦。所以初始化的順序就需要注意。
在某個類的子類中李破,初始化方法里語句的順序并不是隨意的宠哄,我們需要保證在當(dāng)前子類實(shí)例的成員初始化完成后才能調(diào)用父類的初始化方法
class Cat {
var name: String
init() {
name = "cat"
}
}
class Tiger: Cat {
let power: Int
override init() {
power = 10
super.init()
name = "tiger"
}
}
Swift析構(gòu)過程
在一個類的實(shí)例被釋放之前,析構(gòu)函數(shù)被立即調(diào)用嗤攻。用關(guān)鍵字deinit來標(biāo)示析構(gòu)函數(shù)毛嫉,類似于初始化函數(shù)用init來標(biāo)示。析構(gòu)函數(shù)只適用于類類型
析構(gòu)過程原理
Swift 會自動釋放不再需要的實(shí)例以釋放資源
Swift 通過自動引用計(jì)數(shù)(ARC)處理實(shí)例的內(nèi)存管理
通常當(dāng)你的實(shí)例被釋放時不需要手動地去清理妇菱。但是狱庇,當(dāng)使用自己的資源時,你可能需要進(jìn)行一些額外的清理恶耽。
例如,如果創(chuàng)建了一個自定義的類來打開一個文件颜启,并寫入一些數(shù)據(jù)偷俭,你可能需要在類實(shí)例被釋放之前關(guān)閉該文件
在類的定義中,每個類最多只能有一個析構(gòu)函數(shù)缰盏。析構(gòu)函數(shù)不帶任何參數(shù)涌萤,在寫法上不帶括號
deinit {
// 執(zhí)行析構(gòu)過程
}
Swift可選鏈
可選鏈(Optional Chaining)是一種可以請求和調(diào)用屬性淹遵、方法和子腳本的過程,用于請求或調(diào)用的目標(biāo)可能為nil
可選鏈返回兩個值:
- 如果目標(biāo)有值负溪,調(diào)用就會成功透揣,返回該值
- 如果目標(biāo)為nil,調(diào)用將返回nil
多次請求或調(diào)用可以被鏈接成一個鏈川抡,如果任意一個節(jié)點(diǎn)為nil將導(dǎo)致整條鏈?zhǔn)?/p>
可選鏈可替代強(qiáng)制解析
通過在屬性辐真、方法、或下標(biāo)腳本的可選值后面放一個問號(?)崖堤,即可定義一個可選鏈
Swift自動引用計(jì)數(shù)(ARC)
Swift 使用自動引用計(jì)數(shù)(ARC)這一機(jī)制來跟蹤和管理應(yīng)用程序的內(nèi)存
通常情況下我們不需要去手動釋放內(nèi)存侍咱,因?yàn)?ARC 會在類的實(shí)例不再被使用時,自動釋放其占用的內(nèi)存
在有些時候我們還是需要在代碼中實(shí)現(xiàn)內(nèi)存管理
ARC功能:
- 當(dāng)每次使用 init() 方法創(chuàng)建一個類的新的實(shí)例的時候密幔,ARC 會分配一大塊內(nèi)存用來儲存實(shí)例的信息
- 內(nèi)存中會包含實(shí)例的類型信息楔脯,以及這個實(shí)例所有相關(guān)屬性的值
- 當(dāng)實(shí)例不再被使用時,ARC 釋放實(shí)例所占用的內(nèi)存胯甩,并讓釋放的內(nèi)存能挪作他用
- 為了確保使用中的實(shí)例不會被銷毀昧廷,ARC 會跟蹤和計(jì)算每一個實(shí)例正在被多少屬性,常量和變量所引用
- 實(shí)例賦值給屬性偎箫、常量或變量木柬,它們都會創(chuàng)建此實(shí)例的強(qiáng)引用,只要強(qiáng)引用還在镜廉,實(shí)例是不允許被銷毀的
class Person {
let name: String
init(name: String) {
self.name = name
print("\(name) 開始初始化")
}
deinit {
print("\(name) 被析構(gòu)")
}
}
// 值會被自動初始化為nil弄诲,目前還不會引用到Person類的實(shí)例
var reference1: Person?
var reference2: Person?
var reference3: Person?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// 創(chuàng)建Person類的新實(shí)例
reference1 = Person(name: "Runoob")
//賦值給其他兩個變量,該實(shí)例又會多出兩個強(qiáng)引用
reference2 = reference1
reference3 = reference1
//斷開第一個強(qiáng)引用
reference1 = nil
//斷開第二個強(qiáng)引用
reference2 = nil
//斷開第三個強(qiáng)引用娇唯,并調(diào)用析構(gòu)函數(shù)
reference3 = nil
}
=>
Runoob 開始初始化
Runoob 被析構(gòu)
類實(shí)例之間的循環(huán)強(qiáng)引用
可能會寫出這樣的代碼齐遵,一個類永遠(yuǎn)不會有0個強(qiáng)引用。這種情況發(fā)生在兩個類實(shí)例互相保持對方的強(qiáng)引用塔插,并讓對方不被銷毀梗摇。這就是所謂的循環(huán)強(qiáng)引用。
解決實(shí)例之間的循環(huán)強(qiáng)引用
Swift 提供了兩種辦法用來解決你在使用類的屬性時所遇到的循環(huán)強(qiáng)引用問題
- 弱引用
- 無主引用
弱引用和無主引用允許循環(huán)引用中的一個實(shí)例引用另外一個實(shí)例而不保持強(qiáng)引用想许。這樣實(shí)例能夠互相引用而不產(chǎn)生循環(huán)強(qiáng)引用伶授。
對于生命周期中會變?yōu)閚il的實(shí)例使用弱引用。相反的流纹,對于初始化賦值后再也不會被賦值為nil的實(shí)例糜烹,使用無主引用
弱引用實(shí)例
class Module {
let name: String
init(name: String) {
self.name = name
}
var sub: SubModule?
deinit {
print("\(name) 主模塊")
}
}
class SubModule {
let number: Int
init(number: Int) {
self.number = number
}
weak var topic: Module?
deinit {
print("子模塊topic數(shù)為 \(number)")
}
}
var mod: Module?
var sub: SubModule?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
mod = Module(name: "Swift")
sub = SubModule(number: 5)
mod?.sub = sub
sub?.topic = mod
mod = nil
sub = nil
}
無主引用實(shí)例
class Student {
let name: String
var mark: Marks?
init(name: String) {
self.name = name
}
deinit {
print("學(xué)生姓名: \(name)")
}
}
class Marks {
let score: Int
unowned let stu: Student
init(score: Int, stu: Student) {
self.score = score
self.stu = stu
}
deinit {
print("分?jǐn)?shù) \(score)")
}
}
var stu: Student?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
stu = Student(name: "Swift")
stu?.mark = Marks(score: 99, stu: stu!)
stu = nil
}
閉包引起的循環(huán)強(qiáng)引用
循環(huán)強(qiáng)引用還會發(fā)生在當(dāng)你將一個閉包賦值給類實(shí)例的某個屬性,并且這個閉包體中又使用了實(shí)例漱凝。
這個閉包體中可能訪問了實(shí)例的某個屬性疮蹦,例如self.someProperty,或者閉包中調(diào)用了實(shí)例的某個方法茸炒,例如self.someMethod愕乎。
這兩種情況都導(dǎo)致了閉包 "捕獲" self阵苇,從而產(chǎn)生了循環(huán)強(qiáng)引用
弱引用和無主引用
當(dāng)閉包和捕獲的實(shí)例總是互相引用時并且總是同時銷毀時,將閉包內(nèi)的捕獲定義為無主引用
相反的感论,當(dāng)捕獲引用有時可能會是nil時绅项,將閉包內(nèi)的捕獲定義為弱引用
如果捕獲的引用絕對不會置為nil,應(yīng)該用無主引用比肄,而不是弱引用
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
[unowned self] in
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name)>"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name)被析構(gòu)")
}
}
var para: HTMLElement? = HTMLElement(name: "p", text: "hello world")
print(para!.asHTML())
para = nil
=>
<p>hello world</p>
p被析構(gòu)
Swift類型轉(zhuǎn)換
Swift 語言類型轉(zhuǎn)換可以判斷實(shí)例的類型快耿。也可以用于檢測實(shí)例類型是否屬于其父類或者子類的實(shí)例
Swift 中類型轉(zhuǎn)換使用 is 和 as 操作符實(shí)現(xiàn),is 用于檢測值的類型薪前,as 用于轉(zhuǎn)換類型
類型轉(zhuǎn)換也可以用來檢查一個類是否實(shí)現(xiàn)了某個協(xié)議
class Car {
var name: String
init(name: String) {
self.name = name
}
}
class BMW: Car {
let type: String
init(name: String, type: String) {
self.type = type
super.init(name: name)
}
}
class Auto: Car {
let wheels: Int
init(name: String, wheels: Int) {
self.wheels = wheels
super.init(name: name)
}
}
let list = [
BMW(name: "寶馬", type: "X3"),
Auto(name: "大眾", wheels: 4),
BMW(name: "寶馬", type: "X1"),
BMW(name: "寶馬", type: "X5"),
Auto(name: "大眾", wheels: 5),
]
var bmwCount = 0
var autoCount = 0
for item in list {
if item is BMW {
bmwCount += 1
} else if item is Auto {
autoCount += 1
}
}
print("寶馬: \(bmwCount), 大眾: \(autoCount)")
=>
寶馬: 3, 大眾: 2
向下轉(zhuǎn)型
向下轉(zhuǎn)型润努,用類型轉(zhuǎn)換操作符(as? 或 as!)
當(dāng)你不確定向下轉(zhuǎn)型可以成功時,用類型轉(zhuǎn)換的條件形式(as?)示括。條件形式的類型轉(zhuǎn)換總是返回一個可選值(optional value)铺浇,并且若下轉(zhuǎn)是不可能的,可選值將是 nil垛膝。
只有你可以確定向下轉(zhuǎn)型一定會成功時鳍侣,才使用強(qiáng)制形式(as!)。當(dāng)你試圖向下轉(zhuǎn)型為一個不正確的類型時吼拥,強(qiáng)制形式的類型轉(zhuǎn)換會觸發(fā)一個運(yùn)行時錯誤倚聚。
for item in list {
if let show = item as? BMW {
print("BMW品牌: \(show.name)")
} else if let show = item as? Auto {
print("Auto品牌: \(show.name)")
}
}
BMW品牌: 寶馬
Auto品牌: 大眾
BMW品牌: 寶馬
BMW品牌: 寶馬
Auto品牌: 大眾
Any和AnyObject的類型轉(zhuǎn)換
Swift為不確定類型提供了兩種特殊類型別名
- AnyObject可以代表任何class類型的實(shí)例
- Any可以表示任何類型,包括方法類型(function types)
注意:
只有當(dāng)你明確的需要它的行為和功能時才使用Any和AnyObject凿可。在你的代碼里使用你期望的明確的類型總是更好的
var exampleAny: [Any] = []
exampleAny.append(10)
exampleAny.append(0.88)
exampleAny.append("Hello Swift")
exampleAny.append(true)
exampleAny.append(BMW(name: "寶馬", type: "X5"))
for item in exampleAny {
if let int = item as? Int {
print("整型數(shù): \(int)")
} else if let double = item as? Double {
print("浮點(diǎn)型: \(double)")
} else if let string = item as? String {
print("字符串: \(string)")
} else if let bool = item as? Bool {
print("布爾值: \(bool)")
} else if let object = item as? BMW {
print("對象類型: \(object.name)")
} else {
print("其他類型")
}
}
==>
var exampleAny: [Any] = []
exampleAny.append(10)
exampleAny.append(0.88)
exampleAny.append("Hello Swift")
exampleAny.append(true)
exampleAny.append(BMW(name: "寶馬", type: "X5"))
for item in exampleAny {
switch item {
case let someInt as Int:
print("整型: \(someInt)")
case let someDouble as Double:
print("浮點(diǎn)型: \(someDouble)")
case let someString as String:
print("字符串: \(someString)")
case let someBool as Bool:
print("布爾值: \(someBool)")
case let someObject as BMW:
print("對象: \(someObject)")
default:
print("其他未知")
}
}
在一個switch語句的case中使用強(qiáng)制形式的類型轉(zhuǎn)換操作符(as, 而不是 as?)來檢查和轉(zhuǎn)換到一個明確的類型
Swift擴(kuò)展
擴(kuò)展就是向一個已有的類惑折、結(jié)構(gòu)體或枚舉類型添加新功能
擴(kuò)展可以對一個類型添加新的功能,但是不能重寫已有的功能
Swift中的擴(kuò)展可以:
- 添加計(jì)算型屬性和計(jì)算型靜態(tài)屬性
- 定義實(shí)例方法和類型方法
- 提供新的構(gòu)造器
- 定義下標(biāo)
- 定義和使用新的嵌套類型
- 使一個已有類型符合某個協(xié)議
extension SomeType {
// 加到SomeType的新功能寫到這里
}
一個擴(kuò)展可以擴(kuò)展一個已有類型枯跑,使其能夠適配一個或多個協(xié)議
extension SomeType: SomeProtocol, AnotherProtocol {
// 協(xié)議實(shí)現(xiàn)寫到這里
}
計(jì)算型屬性
擴(kuò)展可以向已有類型添加計(jì)算型實(shí)例屬性和計(jì)算型類型屬性
extension Int {
var add: Int {
return self + 100
}
var minus: Int {
return self - 100
}
var multiply: Int {
return self * 3
}
var divide: Int {
return self / 3
}
}
let add = 1.add
let minus = 101.minus
let mul = 5.multiply
let div = 120.divide
print("\(add), \(minus), \(mul), \(div)")
=>
101, 1, 15, 40
構(gòu)造器
擴(kuò)展可以向已有類型添加新的構(gòu)造器
可以讓你擴(kuò)展其它類型惨驶,將你自己的定制類型作為構(gòu)造器參數(shù),或者提供該類型的原始實(shí)現(xiàn)中沒有包含的額外初始化選項(xiàng)
擴(kuò)展可以向類中添加新的便利構(gòu)造器 init()敛助,但是它們不能向類中添加新的指定構(gòu)造器或析構(gòu)函數(shù) deinit()
方法
擴(kuò)展可以向已有類型添加新的實(shí)例方法和類型方法
extension Int {
func repeatContent(summary: () -> ()) {
for _ in 0..<self {
summary()
}
}
}
3.repeatContent {
print("打印3")
}
2.repeatContent {
print("打印2")
}
=>
打印3
打印3
打印3
打印2
打印2
Swift協(xié)議
協(xié)議規(guī)定了用來實(shí)現(xiàn)某一特定功能所必需的方法和屬性
任意能夠滿足協(xié)議要求的類型被稱為遵循(conform)這個協(xié)議
類粗卜,結(jié)構(gòu)體或枚舉類型都可以遵循協(xié)議,并提供具體實(shí)現(xiàn)來完成協(xié)議定義的方法和功能
protocol SomeProtocol {
// 協(xié)議內(nèi)容
}
要使類遵循某個協(xié)議纳击,需要在類型名稱后加上協(xié)議名稱续扔,中間以冒號:分隔,作為類型定義的一部分焕数。遵循多個協(xié)議時纱昧,各協(xié)議之間用逗號,分隔
struct SomeStructure: FirstProtocol, AnotherProtocol {
// 結(jié)構(gòu)體內(nèi)容
}
如果類在遵循協(xié)議的同時擁有父類,應(yīng)該將父類名放在協(xié)議名之前堡赔,以逗號分隔
class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
// 類的內(nèi)容
}
Swift訪問控制
Swift 中砌些,訪問控制(Access Control)是一種用于限制代碼模塊對其他代碼模塊的訪問權(quán)限的機(jī)制。通過訪問控制,可以控制代碼中各個部分的可見性和可訪問性存璃,以便于提高代碼的安全性、可維護(hù)性和可復(fù)用性
Swift 提供了以下幾種訪問級別:
- open 最高訪問級別雕拼,可以被定義模塊外的代碼訪問和繼承
- public 可以被定義模塊外的代碼訪問纵东,但不能被繼承
- internal: 默認(rèn)訪問級別,可以被同一模塊中的任何代碼訪問
- fileprivate: 只能在定義的文件內(nèi)部訪問
- private: 只能在定義的作用域內(nèi)部訪問
訪問控制規(guī)則:
- 一個實(shí)體不能被具有更低訪問級別的實(shí)體定義
- 函數(shù)的訪問級別不能高于其參數(shù)類型和返回類型的訪問級別
- 類的訪問級別不能高于其父類的訪問級別
- 類型的訪問級別會影響其成員的訪問級別