Swift小記

菜鳥教程-Swift

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.png
let a = 1+ 2
==> 報錯
let a = 1+ 2.png
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)算符:

  1. 閉區(qū)間運(yùn)算符: 1...5 => 1、2携龟、3兔跌、4、5
  2. 開區(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ù)類型和返回類型的訪問級別
  • 類的訪問級別不能高于其父類的訪問級別
  • 類型的訪問級別會影響其成員的訪問級別
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末啥寇,一起剝皮案震驚了整個濱河市偎球,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌辑甜,老刑警劉巖衰絮,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異磷醋,居然都是意外死亡猫牡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進(jìn)店門邓线,熙熙樓的掌柜王于貴愁眉苦臉地迎上來淌友,“玉大人,你說我怎么就攤上這事骇陈≌鹜ィ” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵你雌,是天一觀的道長器联。 經(jīng)常有香客問我,道長婿崭,這世上最難降的妖魔是什么拨拓? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮逛球,結(jié)果婚禮上千元,老公的妹妹穿的比我還像新娘。我一直安慰自己颤绕,他們只是感情好幸海,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著奥务,像睡著了一般物独。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上氯葬,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天挡篓,我揣著相機(jī)與錄音,去河邊找鬼。 笑死官研,一個胖子當(dāng)著我的面吹牛秽澳,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播戏羽,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼担神,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了始花?” 一聲冷哼從身側(cè)響起妄讯,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎酷宵,沒想到半個月后亥贸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡浇垦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年炕置,在試婚紗的時候發(fā)現(xiàn)自己被綠了罗丰。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片踱承。...
    茶點(diǎn)故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖渐裸,靈堂內(nèi)的尸體忽然破棺而出煌抒,到底是詐尸還是另有隱情仍劈,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布寡壮,位于F島的核電站贩疙,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏况既。R本人自食惡果不足惜这溅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望棒仍。 院中可真熱鬧悲靴,春花似錦、人聲如沸莫其。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽乱陡。三九已至浇揩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間憨颠,已是汗流浹背胳徽。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工积锅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人养盗。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓缚陷,卻偏偏與公主長得像,于是被迫代替她去往敵國和親爪瓜。 傳聞我的和親對象是個殘疾皇子蹬跃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1、隱式解析可選類型 有時候在程序架構(gòu)中铆铆,第一次被賦值之后,可以確定一個可選類型總會有值丹喻,這時候每次使用時都判斷和...
    Mr_xuy閱讀 482評論 1 4
  • 常量與變量使用let來聲明常量薄货,使用var來聲明變量。聲明的同時賦值的話碍论,編譯器會自動推斷類型谅猾。值永遠(yuǎn)不會被隱式轉(zhuǎn)...
    莫_名閱讀 450評論 0 1
  • Swift屬性 Swift屬性將值跟特定的類,結(jié)構(gòu)體鳍悠,枚舉關(guān)聯(lián)税娜。分為存儲屬性和計(jì)算屬性,通常用于特定類型的實(shí)例藏研。屬...
    小小廚師閱讀 855評論 0 0
  • 一敬矩、簡介 蘋果于2014年WWDC(蘋果開發(fā)者大會)發(fā)布的新開發(fā)語言,可與Objective-C共同運(yùn)行于Mac ...
    Silence_xl閱讀 90評論 0 1
  • 標(biāo)簽(空格分隔): 未分類 基礎(chǔ)(相關(guān)概念) 1.元祖 元組(tuples)把多個值組合成一個復(fù)合值蠢挡。元組內(nèi)的值可...
    一生信仰閱讀 602評論 0 0