學(xué)習(xí)不像愛情。愛情你一認真就輸了。學(xué)習(xí)你一認真就贏了。
A plant may produce new flowers; man is young but once.
(花有重開日,人無再少年)
OOP: Object Oriented Programming 面向?qū)ο蟮某绦蛟O(shè)計
Swift語言中,不僅類具有面向?qū)ο蟮奶卣鳎?strong>結(jié)構(gòu)體與枚舉都具有面向?qū)ο蟮奶卣鳌5?strong>類是引用類型,結(jié)構(gòu)體與枚舉是值類型(作為參數(shù)需要修改內(nèi)容時有區(qū)別,類直接傳對象 其他傳地址&)。
類的“實例”一般稱為“對象”,但是,枚舉與結(jié)構(gòu)體的“實例”不能稱之為“對象”,因為它們不是真正的面向?qū)ο箢愋?/strong>。只是包含了面向?qū)ο蟮奶攸c。
1、枚舉 - 值類型
-
枚舉 = 成員值 + 相關(guān)值 (成員值 后 可加 原始值)
-
成員值
-
定義 - 枚舉的成員值 默認情況下 不是整數(shù)類型0,1,...
enum WeekDays { case Monday case Tuesday case Wednesday case Thursday case Friday // 注意:如果枚舉成員類型不同這樣寫case c(Character) } // 簡易寫法 enum weekDays: Int{ case Monday, Tuesday, Wednesday, Thursday, Firday } -
賦值
var day = weekDays.Monday // 枚舉類型名稱.成員值 day = .Monday // .成員值 能這么用的前提:必須有上下文,Swift能判斷出類型 switch day { case .Monday: print("Monday") case .Tuesday: print("Tuesday") case .Wednesday: print("Wednesday") case .Thursday: print("Thursday") case .Firday: print("Firday") // default: // print("default") /** default分支在枚舉中可以省略,使用其他類型是不允許省略的。 只要枚舉中case列舉完畢所有可能值, default可省略,不省略有warning。 如果 存在default同時不存在warning,那么可以把case .Firday 分支去掉 (其實去掉任何一個分支都可以,只要滿足所有可能性全包括了即可)*/ }
-
-
原始值(raw value)
-
可以是字符、字符串、整數(shù)、浮點數(shù)等
// 1、加入數(shù)據(jù)類型Int 2、加入默認值0,1,2,... enum weekDays: Int{ // 之后自動加1。也可以case Monday = 0 case Tuesday = 1...分開寫,也可只給第一個成員賦值,后面成員值會依次+1 case Monday = 0, Tuesday, Wednesday, Thursday, Firday } let friday = weekDays.Firday.rawValue // 4 成員值->原始值 let thursday = weekDays(rawValue: 3) // Thursday 原始值->成員值,是 調(diào)用枚舉的 構(gòu)造函數(shù) 初始化 枚舉的實例。
-
-
相關(guān)值
/** 枚舉的相關(guān)值 枚舉中成員值 相關(guān)值 一般首字母大寫,就像OC中的枚舉前面也是大寫(前綴是大寫的) */ enum Figure{ case Rectangle(Int, Int) case Circle(Int) } func printFigure(figure: Figure){ switch figure { /** 自帶值的提?。?! 如果某個相關(guān)值元組中字段類型一致,需要全部提取, 可以將字段前面的let或者var移到相關(guān)值前面。 case let .Rectangle(width, height): case let .Circle(radius): 字段是一個的也可以,但是沒有必要 */ case .Rectangle(let width, let height): print("矩形的寬\(width)高\(height)") case .Circle(let radius): print("圓的半徑\(radius)") } } printFigure(figure: Figure.Rectangle(2, 1)) printFigure(figure: Figure.Circle(2)) // 打印 矩形的寬2高1 圓的半徑2
2、結(jié)構(gòu)體 - 值類型
Swift重視結(jié)構(gòu)體,把結(jié)構(gòu)體作為實現(xiàn)面向?qū)ο蟮闹匾侄巍2粌H可以定義成員變量也就是屬性,還可以定義成員方法??梢钥醋魇且环N輕量級的類。(而其他語言中的結(jié)構(gòu)體 只能定義一組相關(guān)的成員變量)
-
結(jié)構(gòu)體的定義 : struct + 結(jié)構(gòu)體名稱{ 成員變量 }
// 部門(下文要用到此結(jié)構(gòu)體實例化) - 部門與員工是1 : n的關(guān)系(1 對 多的關(guān)系) struct Department{ var no: Int = 0 var name: String = "" } -
結(jié)構(gòu)體的實例化--如果要給結(jié)構(gòu)體的成員變量賦值,用var不用let。而類一般用let
var dept1 = Department() // 有屬性賦值必須是var dept1.no = 10 dept1.name = "Sales"
3、類 - 引用類型
-
類的定義
// 員工類(下文要用此類實例化) - 員工與部門是n : 1的關(guān)系 class Employee{ var no: Int = 0 var name: String = "" var job: String? var salory: Double = 0.0 var dept: Department? // 結(jié)構(gòu)體類型所在部門屬性 } -
類的實例化--類一般聲明為let常量,由于類是引用數(shù)據(jù)類型,聲明為let常量只是說明不能修改引用(比如下面的emp1),但是可以通過內(nèi)存地址拿到對應(yīng)的對象,修改對象內(nèi)部的屬性
let emp1 = Employee() emp1.no = 1000 emp1.name = "Martin" emp1.job = "Salesman" emp1.salory = 1250
4、 值類型與引用類型
-
類是引用類型,其他類型全是值類型??!(再記一遍,重要)
引用類型 與 值類型 修改內(nèi)容舉例:// 創(chuàng)建實例 var dept = Department() // var dept.no = 10 dept.name = "Sales" let emp = Employee() emp.no = 1000 emp.name = "Martin" emp.job = "Salesman" emp.salory = 1250 ================= 值類型分割線 ================ #warning 值類型 /** 不加inout,傳入dept,編譯失敗,修改不成功,說明了結(jié)構(gòu)體是值類型, 引用類型不用加inout 傳入引用對象即可修改成功 */ func updateDept(dept: inout Department){ dept.name = "Research" } print("Deparment更新前\(dept.name)") // "Sales" updateDept(dept: &dept) print("Deparment更新后\(dept.name)") // "Research" ================= 引用類型分割線 ================ #warning 引用類型 func updateEmp(emp: Employee){ emp.job = "Clerk" } print("Employment更新前\(emp.job!)") // "Salesman" job是可選類型 需要解包 updateEmp(emp: emp) print("Employment更新后\(emp.job!)") // "Clerk"
5、引用類型的比較
-
對于引用類型的實例比較,比如類的實例比較 只能用=== 與 !==
-
結(jié)構(gòu)體與類實例化
var dept1 = Department() // var 結(jié)構(gòu)體 dept1.no = 10 dept1.name = "Sales" var dept2 = Department() // var 結(jié)構(gòu)體 dept2.no = 10 dept2.name = "Sales" let emp1 = Employee() // 對象 emp1.no = 1000 emp1.name = "Martin" emp1.job = "Salesman" emp1.salory = 1250 let emp2 = Employee() // 對象 emp2.no = 1000 emp2.name = "Martin" emp2.job = "Salesman" emp2.salory = 1250 -
類實例比較 & 結(jié)構(gòu)體屬性的比較
// 比較是否實例相等 if emp1 !== emp2{ // false : 不同的對象 print("emp1 !== emp2") } if emp1 === emp1 { // true : 同一個對象 print("emp1 === emp1") } if dept1.no == dept2.no { // true : 值相等 print("dept1.no == dept2.no") } -
結(jié)構(gòu)體的實例比較 - 編譯失敗
if dept1 == dept2 { // 編譯失敗:對于枚舉 與結(jié)構(gòu)體 直接比較編譯失敗,需要運算符重載 print("dept1 == dept2") }else{ print("dept1 != dept2") } -
運算符重載 - 編譯成功
// 運算符重載:每對屬性分別比較。調(diào)用d1 == d2固定調(diào)用寫法 func ==(d1: Department, d2: Department) -> Bool{ return d1.no == d2.no && d1.name == d2.name } func !=(d1: Department, d2: Department) -> Bool{ return d1.no != d2.no || d1.name != d2.name } 打印結(jié)果: dept1 == dept2注明: 判斷中dept1 == dept2語句調(diào)用該運算符的重載函數(shù),對于有多個判斷是否相等的重載函數(shù),應(yīng)該調(diào)用哪個重載函數(shù)由重載函數(shù)的參數(shù)類型(如:Department)決定。
-
6、 類型嵌套
關(guān)于類型嵌套,它會使程序結(jié)構(gòu)變得不清晰,可讀性差。
優(yōu)點:支持訪問外部類的成員,成員包括:方法,屬性,枚舉,結(jié)構(gòu)體等嵌套類型
-
訪問:對象名.屬性名,對象名.枚舉實例,對象名.結(jié)構(gòu)體實例,類名.枚舉名.枚舉成員值(.rawValue),
不能對象名.枚舉名,對象名.結(jié)構(gòu)體名// 類型嵌套的使用 class Employee{ var no: Int = 0 var name: String = "" var job: String? var salary: Double = 0 var dept: Department = Department() var day: WeekDays = WeekDays.Friday struct Department { // 里一層 var no: Int = 10 var name: String = "SALES" } enum WeekDays { // 里一層 case Monday case Tuesday case Wednesday case Thursday case Friday struct Day { // 里二層 static var message: String = "Today is..." } } } ============= 實例化分割線 ========== var emp = Employee() print(emp.dept.name) print(emp.day) // 對象emp不能調(diào)用結(jié)構(gòu)體 枚舉等名 let friday = Employee.WeekDays.Friday if emp.day == friday { print("相等") } print(Employee.WeekDays.Day.message) // 一層嵌套一層。類名稱只能直接調(diào)用枚舉名稱 結(jié)構(gòu)體名稱 //print(Employee.WeekDays.Day) 編譯失敗, 括號內(nèi)必須是字符串,枚舉沒有成員默認值
7、可選鏈
可選鏈是在類型嵌套中常用的。比如外部類Employee有個屬性不確定有沒有值的存在(eg: var dept: Department?),這個屬性是個嵌套類類型(成員有var comp: Company?),Company又是一個嵌套類類型(成員有var name: String = "張三")。
-
如果要訪問name,會這么做:
let emp = Employee() print(emp.dept!.comp!.name) // 顯式拆包 // 但是顯式拆包有個弊端,如果可選鏈中某個環(huán)節(jié)為nil,將會導(dǎo)致代碼運行錯誤 // fatal error: unexpectedly found nil while unwrapping an Optional value // (之前基本數(shù)據(jù)類型賦值對于nil是用可選綁定解決的) print(emp.dept?.comp?.name) // 可選鏈 // 如果某個環(huán)節(jié)為nil,不會拋出異常,會把nil返回給引用者
注意:在可選鏈中,最后的字段不能再加問號,會報錯:error: '?' must be followed by a call, member lookup, or subscript