【Swift】基础(4)—— 枚举、结构体和类

1,802 阅读7分钟

存储属性和计算属性

存储属性

存储属性,把常量或变量的值作为实例的一部分。

存储属性的作用是把常量或变量的值作为实例的一部分,使用var关键字定义的属性为变量存储属性,使用let关键字定义的属性为常量存储属性。

计算属性

计算属性,它计算一个值,类似于方法的功能,提供了一个处理数据的入口与出口。

计算属性可以用于类、结构和枚举里,存储属性只能用于类和结构体里。

计算属性不直接存储值,而是提供一个getter来获取值,然后用一个可选的setter来间接设置其他属性或变量值,getter方法通过访问触发,setter方法通过赋值触发。

例:

class newClass {
    var givenName = "张"
    var firstName = "小龙"
    var allName: String {
        get {
            return givenName + firstName
        }
        
    }
}

在Swift中,类在初始化的时候它的属性必须都被初始化。如果不想设置某个属性的默认值,则可使用"?"把它加入可选链中,声明为可选类型,如var name:String?


枚举

枚举是一组有共同特性的数据的集合。

与OC中的枚举不同的是,Swift的枚举成员在被创建时不会有默认的整形值,而是其枚举的类型。

定义

使用 enum 关键词来创建枚举并且把它们的整个定义放在一对大括号内。

枚举定义时可以设置其 原始值 ,原始值可以是字符串,字符,或者任何整型值或浮点型值。每个原始值在它的枚举声明中必须是唯一的:

enum 枚举类型名称: 原始值类型  {
   case 枚举值1
   case 枚举值2
   // ...
}

例如:

// 整数
enum Movement:Int {
    case left
    case right
    case top
    case bottom
}
// 也可以简写成
enum Movement:Int {
    case left,right,top,bottom,
}

当使用整数作为原始值时,隐式赋值的值依次递增1。如果第一个值没有被赋初值,将会被自动置为0。

// 字符串
enum Area: String {
    case DG = "dongguan"
    case GZ = "guangzhou"
    case SZ = "shenzhen"
}

也可以设置其 相关值 ,相关值在创建一个基于枚举成员的新常量或变量时才会被设置(类似于对象中的属性值),如:

enum Student{
    case Name(String)
    case Mark(Int,Int,Int)
}
var studDetails = Student.Name("Runoob")
var studMarks = Student.Mark(98,97,95)
switch studMarks {
    case .Name(let studName):
        print("学生的名字是: \(studName)。")
    case .Mark(let Mark1, let Mark2, let Mark3):
        print("学生的成绩是: \(Mark1),\(Mark2),\(Mark3)。")
}

嵌套枚举

枚举中可以嵌套枚举,如:

enum Area {
    enum DongGuan {
        case NanCheng
        case DongCheng
    }
    
    enum GuangZhou {
        case TianHe
        case CheBei
    }
}

print(Area.DongGuan.DongCheng)

属性

枚举中不能直接添加属性,但是可以创建计算属性,如:

enum Device {
  case iPad, iPhone
  var year: Int {
    switch self {
        case iPhone: return 2007
        case iPad: return 2010
     }
  }
}

方法

Swift的枚举中也可以添加实例方法和类方法,具体参看上一篇文章。

结构体

结构体是构建代码所用的一种通用且灵活的构造体。

Swift中的结构体与C++和OC中的结构体有很大的差别,C++和OC中的结构体只能定义一组相关的成员变量,而Swift中的结构体不仅可以定义属性,还可以定义方法。因此,我们可以把Swfit结构体看做是一种轻量级的类。

Swift语言却非常重视结构体,把结构体作为实现面向对象的重要手段。

与类的区别

Swift中类和结构体的不同处在于:

结构体不具有继承性

结构体不具备运行时强制类型转换

结构体不具备使用析构器的能力

结构体不具备使用引用计数的能力

定义

结构体定义使用struct关键字

struct 结构体名 {
   ……
}

构造函数

  • 默认情况下,系统会为每一个结构体提供一个默认的构造函数,并且该构造函数,要求给每一个成员属性进行赋值
  • 构造函数都是以 init 开头,并且构造函数不需要返回值
  • 在构造函数结束时,必须保证所有的成员属性都被初始化

例:

struct MarkStruct {
    var mark1: Int
    var mark2: Int
    var mark3: Int
    
    // 自己的构造函数
    init(whStr:String) {
        let arr = whStr.components(separatedBy: ",")
        let m1 = arr[0]
        let m2 = arr[1]
        let m23= arr[2]
        self.mark1= Int(m1) ?? 0
        self.mark2= Int(m2) ?? 0
        self.mark3= Int(m3) ?? 0
    }
}

// 使用
// 调用自动生成的构造函数
var marks = MarkStruct(mark1: 98, mark2: 96, mark3: 100)
// 调用增加的构造函数
var marks = MarkStruct(whStr: "98,96,100")

方法

结构体中的实例方法和类方法的使用可以参考上一篇文章。

当需要在方法中修改到结构体和枚举的属性值时(一般不建议这么做),需要在方法前加上mutating关键字,如:

struct Size {
    var width:Double
    var height:Double = 0.0
    
    mutating func changeWidth(width: Double) {
        self.width = width
    }
}

类是构建代码所用的一种通用且灵活的构造体,可以为类定义属性(常量、变量)和方法。

Swift 并不要求为自定义类去创建独立的接口和实现文件。所要做的是在一个单一文件中定义一个类,系统会自动生成面向其它代码的外部接口。

类的特性

类与结构体的共同特性有:

  • 定义属性用于存储值
  • 定义方法用于提供功能
  • 定义附属脚本用于访问值
  • 定义构造器用于生成初始化值
  • 通过扩展以增加默认实现的功能
  • 符合协议以对某类提供标准功能

此外,类还有以下的特性:

  • 允许一个类继承另一个类的特征
  • 类型转换允许在运行时检查和解释一个类实例的类型
  • 解构器允许一个类实例释放任何其所被分配的资源
  • 引用计数允许对一个类的多次引用

定义

Swift中使用class关键字来定义一个类,格式如下:

class 类名 {
   ……
}

构造函数

类的构造函数的定义与使用与结构体大体相似。

不同的是,如果在类中自定义了构造函数,则会覆盖掉自动生成的构造函数,且自动生成的构造函数中不强制要求给每个属性进行赋值。

方法

类中的实例方法与类方法的使用可以参考上一篇文章。

恒等运算符

类是引用类型,有可能有多个常量和变量在后台同时引用某一个类实例。 恒等运算符(===!==)能够判定两个常量或者变量是否引用同一个类实例。

类和结构体的选择

结构体实例总是通过值传递,类实例总是通过引用传递。

即:

结构体赋值时可以看成是值的拷贝,

类赋值时可以看成是类的实例的地址的传递。

在考虑一个项目的数据构造和功能的时候,就需要决定每个数据构造是定义成类还是结构体。

当符合一条或多条以下条件时,请考虑构建结构体:

  • 结构体的主要目的是用来封装少量相关简单数据值。
  • 有理由预计一个结构体实例在赋值或传递时,封装的数据将会被拷贝而不是被引用。
  • 任何在结构体中储存的值类型属性,也将会被拷贝,而不是被引用。
  • 结构体不需要去继承另一个已存在类型的属性或者行为。

Swift里更推荐使用值类型变量(struct)而不是引用类型(class)的变量,Swift中许多常见的数据类型、字符串、集合类型,以及结构体和枚举都是值类型而非引用类型,值类型的变量在赋值时会自动进行一次低消耗的值拷贝,对比对象的copy要更加高效而且不存在线程安全问题。

参考文章

Swift 枚举

Swift 结构体

Swift 类

Swift中结构体和类的比较