Swift3.x - 类和结构体

类的介绍和定义

  • Swift也是一门面向对象的开发语言。
  • 面向对象的基础就是类,类产生对象。
  • Swift如何定义类:
    • class关键字定义类
    class 类名: SuperClass {
          //定义属性和方法
    

}

* 使用注意:
* 定义类的时候,可以没有父类,那么该类就是根类
* 通常情况下定义定义类时,继承自NSObject

**如何定义类的属性**
* Swift中类的属性有多种:
* 存储属性:存储实例的常量和变量
* 计算属性:通过某种方式计算出来的属性
* 类属性:与整个类相关的属性
* 存储属性
  ```
  class person: NSObject{
      //存储属性
      var age = 0
      var name: String?
  }

  let child = person()
  child.age = 18
  child.name = "小明"

  if let name = child.name {
      print("\(name)今年\(child.age)了")
  }
  //结果:小明今年18了
  ```
* 计算属性
在类中声明的计算属性,这个属性可以由类中定义的函数来完成,但是苹果官方并不见这种实现方式,因为计算属性的方式更加简单明了,下面就来实现以下某个人的在某段时间内完成跑步的平均时速。

class person: NSObject{

  var time = 2
  var startSpeed = 10.0
  var hightSpeed = 20.0
  var endSpeed = 5.0

   //推荐
   var averageSpeed: Double {
       return (startSpeed + hightSpeed + endSpeed) * 0.5
   }
   //不推荐
   func averageSpeedFunction() -> Double {
      return (startSpeed + hightSpeed + endSpeed) * 0.5
  }

}

let child = person()
child.averageSpeedFunction()
child.averageSpeed

* 类属性
类属性是和整个类相关的属性,而且是通过类名来访问。常见于单例!

class person: NSObject{

  //定义某个人有书籍的数量
  static var book = 0

}

person.book = 2
//结果:2

**类的构造函数**
* 构造函数
  * 构造函数类似于OC中的初始化方法:init方法
  * 默认情况下创建某个类时,必然会调用一个构造函数
  * 即便开发者没有构建构造函数,编译器也会提供默认的构造函数
  * 如果继承自NSObject可以对父类的构造函数进行重写
* 构造函数的基本使用
  * 类的属性必须有值
  * 如未在定义时初始化值,可以在构造函数中赋值,通过传递参数,初始化类对象。
      ```
      class person: NSObject{
  
          var name: String?
          var height = 0.0
          //重写父类的构造方法
          //如果重写父类的构造方法,在实例化此类时,Xcode会提示这个方法,如果未重写,Xcode只会提示,我们自定义的构造方法!
          override init(){
              super.init()
          }
          //自定义构造方法
          init(name: String, height: Double) {
              self.name = name
              self.height = height
          }
  
      }

      let child = person(name: "小明", height: 1.88)
      child.name
      child.height
      //结果:小明 1.88
      ```
  * 通过字典参数实例化类对象
    ```
      class person: NSObject{
  
      var name: String?
      var height = 0.0
      //重写父类的构造方法
      override init(){
           super.init()
      }
       //自定义构造方法
      init(name: String, height: Double) {
           self.name = name
           self.height = height
      }
  
      init(dict: [String : AnyObject]) {
             //此种写法会报错,因为从字典中取出的值为AnyObject?可选类型,直接赋值会报错!
             //self.name = dict["name"]
             //self.height = dict["height"]

             //解决方法1:
             //as? 转换符 将as?左侧的类型转换成as?右侧的类型的可选类型
             name = dict["name"] as? String
             //as! 转换符 将as!左侧的类型转换成as! 右侧的类型的可选类型
             height = dict["height"] as! Double
             //但是此种写法同时有带来了新的问题,强制解包是很危险的操作,会造成程序crash
              
             //解决方法2:
             name = dict["name"] as? String
             //可选绑定
             if let tempHeight = dict["height"] as? Double {
                    height = tempHeight
             }
       }
      }
      let child = person(dict: ["name":"小明" as AnyObject, "height": 1.90 as AnyObject])
    ```
    利用KVC实现构造函数实现
    ```
        class person: NSObject{
  
        var name: String?
        var height = 0.0
        //重写父类的构造方法
        override init(){
            super.init()
        }
        //自定义构造方法
        init(name: String, height: Double) {
            self.name = name
            self.height = height
        }
        //KVC
        init(dict: [String : AnyObject]) {
            super.init()
            setValuesForKeys(dict)
        }
        //防止传入的字典存在未知的键值->报错
        override func setValue(_ value: Any?, forUndefinedKey key: String) {}
    }
    let child = person(dict: ["name":"小明" as AnyObject, "height": 1.90 as AnyObject, "weight": 100 as AnyObject])
    child.name
    child.height
    //结果:小明 1.9
    ```

**类的属性监听器**
* 在OC中我们可以重写set方法来监听属性的改变
* Swift中可以通过属性观察者来监听和响应属性的改变
* 通常监听存储属性和类属性
* 通过设置以下方法来定义观察者
  * willSet:将在属性值即将改变时调用
  * didSet:将在属性值改变后调用
  class person: NSObject{

  var name: String?{
      willSet{
          print("\(name)")
      }
    
      didSet{
          print("\(name)")
      }
  }

}
let child = person()
child.name = "小明"


**结构体的介绍和定义**
结构体与类存在很多共同点:
* 定义属性用于存储值
* 定义方法用于提供功能
* 定义下标操作使得可以通过下标语法来访问实例所包含的值
* 定义构造器用于生成初始化值
* 通过扩展以增加默认实现的功能
* 实现协议以提供某种标准功能

* Swift中如何定义结构体:
  * struct关键字定义结构体

struct 结构体名{
//结构体属性or方法
}


**结构体实例化**
结构体实例化和类实例化非常相似:

struct SomeStruct{
//结构体属性or方法
var width = 0
var height = 0
}
//实例化结构体
var someStruct = SomeStruct()

在Swift中,结构体可以直接修改结构体的子属性的值,这点是与OC不同之处!

import UIKit

struct SomeStruct{
//结构体属性or方法
var width = 0
var height = 0
}

var someStruct = SomeStruct()
someStruct.height = 100
someStruct.height
//结果:someStruct.height值为100

**结构体的逐一构造器**
结构体存在逐一构造器,而类中默认是不存在的!我们可以自定义构造函数来完成逐一构造器,上述类的自定义构造方法其实就是自定义的逐一构造器方法!

struct SomeStruct{
//结构体属性or方法
var width = 0
var height = 0
}

var someStruct = SomeStruct(width: 66, height: 88)
someStruct.height
//结果:88
someStruct.width
//结果:66

**结构体与类之间的选择**

�结构体总是通过值传递(值类型),类总是通过引用传递(引用类型)!
按照通用的准则,当符合一条或多条以下条件时,请考虑构建结构体:
* 该数据结构的主要目的是用来封装少量相关简单数据值。
* 有理由预计该数据结构的实例在被赋值或传递时,封装的数据将会被拷贝而不是被引用。
* 该数据结构中储存的值类型属性,也应该被拷贝,而不是被引用。
* 该数据结构不需要去继承另一个既有类型的属性或者行为。

######注意:
在Swift中字符串、数组、字典均为结构体的形式实现(OC中均为类的形式实现)。拷贝行为看起来似乎总会发生。然而,Swift 在幕后只在绝对必要时才执行实际的拷贝。Swift 管理所有的值拷贝以确保性能最优化,所以你没必要去回避赋值来保证性能最优化。

Zeb
参考地址:https://github.com/numbbbbb/the-swift-programming-language-in-chinese

推荐阅读更多精彩内容