Swift(四 面向?qū)ο驩OP特征)

學(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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容