Swift(四 面向对象OOP特征)

学习不像爱情。爱情你一认真就输了。学习你一认真就赢了。
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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容