Swift(四 面向对象OOP特征)

作者: DSA碼侬 | 来源:发表于2017-08-16 13:52 被阅读35次

    学习不像爱情。爱情你一认真就输了。学习你一认真就赢了。
    A plant may produce new flowers; man is young but once.
    (花有重开日,人无再少年)

    • OOP: Object Oriented Programming 面向对象的程序设计

    • Swift语言中,不仅具有面向对象的特征,结构体枚举都具有面向对象的特征。但是类是引用类型,结构体与枚举是值类型(作为参数需要修改内容时有区别,类直接传对象 其他传地址&)。

    • 的“实例”一般称为“对象”,但是,枚举结构体的“实例”不能称之为“对象”,因为它们不是真正的面向对象类型。只是包含了面向对象的特点。

    1、枚举 - 值类型

    • 枚举 = 成员值 + 相关值 (成员值 后 可加 原始值)
    • 成员值

      • 定义 - 枚举的成员值 默认情况下 不是整数类型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)

      • 可以是字符、字符串、整数、浮点数等

         // 1、加入数据类型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 原始值->成员值,是 调用枚举的 构造函数 初始化 枚举的实例。
        
    • 相关值

              /** 
              枚举的相关值
              枚举中成员值 相关值 一般首字母大写,就像OC中的枚举前面也是大写(前缀是大写的)
              */
          enum Figure{
               case Rectangle(Int, Int)  
               case Circle(Int)
            }
      
      
          func printFigure(figure: Figure){
      
           switch figure {
               /**
                 自带值的提取!!
                 如果某个相关值元组中字段类型一致,需要全部提取,
                 可以将字段前面的let或者var移到相关值前面。
                 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、结构体 - 值类型

    • Swift重视结构体,把结构体作为实现面向对象的重要手段。不仅可以定义成员变量也就是属性,还可以定义成员方法。可以看作是一种轻量级的类。(而其他语言中的结构体 只能定义一组相关的成员变量)

    • 结构体的定义 : struct + 结构体名称{ 成员变量 }

      // 部门(下文要用到此结构体实例化)  -   部门与员工是1 : n的关系(1 对 多的关系)
      struct Department{
           var no: Int = 0
           var name: String = ""  
      }
      
    • 结构体的实例化--如果要给结构体的成员变量赋值,用var不用let。而类一般用let

      var dept1 = Department()  // 有属性赋值必须是var
      dept1.no = 10
      dept1.name = "Sales"
      

    3、类 - 引用类型

    • 类的定义

      // 员工类(下文要用此类实例化)  -  员工与部门是n : 1的关系 
      class Employee{
      
         var no: Int = 0
         var name: String = ""
         var job: String?
         var salory: Double = 0.0
      
         var dept: Department?   // 结构体类型所在部门属性
      }
      
    • 类的实例化--类一般声明为let常量,由于类是引用数据类型,声明为let常量只是说明不能修改引用(比如下面的emp1),但是可以通过内存地址拿到对应的对象,修改对象内部的属性

      let emp1 = Employee()
      emp1.no = 1000
      emp1.name = "Martin"
      emp1.job = "Salesman"
      emp1.salory = 1250
      

    4、 值类型与引用类型

    • 类是引用类型,其他类型全是值类型!!(再记一遍,重要)
      引用类型 与 值类型 修改内容举例:

       // 创建实例
       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,编译失败,修改不成功,说明了结构体是值类型,
       引用类型不用加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、引用类型的比较

    • 对于引用类型的实例比较,比如类的实例比较 只能用=== 与 !==

      • 结构体与类实例化

        var dept1 = Department()  // var  结构体
        dept1.no = 10
        dept1.name = "Sales"
        
        var dept2 = Department()  // var  结构体
        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
        
      • 类实例比较 & 结构体属性的比较

         // 比较是否实例相等
         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")
         }
        
      • 结构体的实例比较 - 编译失败

         if dept1 == dept2 {  // 编译失败:对于枚举 与结构体 直接比较编译失败,需要运算符重载
               print("dept1 == dept2")
          }else{
               print("dept1 != dept2")
          }
        
      • 运算符重载 - 编译成功

        // 运算符重载:每对属性分别比较。调用d1 == d2固定调用写法
        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
        }
        打印结果:  dept1 == dept2
        

        注明: 判断中dept1 == dept2语句调用该运算符的重载函数,对于有多个判断是否相等的重载函数,应该调用哪个重载函数由重载函数的参数类型(如:Department)决定。

    6、 类型嵌套

    • 关于类型嵌套,它会使程序结构变得不清晰,可读性差。

    • 优点:支持访问外部类的成员,成员包括:方法,属性,枚举,结构体等嵌套类型

    • 访问:对象名.属性名,对象名.枚举实例,对象名.结构体实例,类名.枚举名.枚举成员值(.rawValue),
      不能对象名.枚举名,对象名.结构体名

         // 类型嵌套的使用
      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不能调用结构体  枚举等名
      
         let friday = Employee.WeekDays.Friday
         if emp.day == friday {
               print("相等")
          }
         print(Employee.WeekDays.Day.message) // 一层嵌套一层。类名称只能直接调用枚举名称 结构体名称
         //print(Employee.WeekDays.Day)   编译失败, 括号内必须是字符串,枚举没有成员默认值
      

    7、可选链

    • 可选链是在类型嵌套中常用的。比如外部类Employee有个属性不确定有没有值的存在(eg: var dept: Department?),这个属性是个嵌套类类型(成员有var comp: Company?),Company又是一个嵌套类类型(成员有var name: String = "张三")。

    • 如果要访问name,会这么做:

         let emp = Employee()
         print(emp.dept!.comp!.name)   // 显式拆包
      // 但是显式拆包有个弊端,如果可选链中某个环节为nil,将会导致代码运行错误
      // fatal error: unexpectedly found nil while unwrapping an Optional value
      // (之前基本数据类型赋值对于nil是用可选绑定解决的)
        
         print(emp.dept?.comp?.name)   // 可选链  
       // 如果某个环节为nil,不会抛出异常,会把nil返回给引用者
      

    注意:在可选链中,最后的字段不能再加问号,会报错:error: '?' must be followed by a call, member lookup, or subscript

    相关文章

      网友评论

        本文标题:Swift(四 面向对象OOP特征)

        本文链接:https://www.haomeiwen.com/subject/xywurxtx.html