swift简单总结(十九)—— 类和结构体

版本记录

版本号 时间
V1.0 2017.07.28

前言

  我是swift2.0的时候开始接触的,记得那时候还不是很稳定,公司的项目也都是用oc做的,并不对swift很重视,我自己学了一段时间,到现在swift3.0+已经出来了,自己平时也不写,忘记的也差不多了,正好项目这段时间已经上线了,不是很忙,我就可以每天总结一点了,希望对自己对大家有所帮助。在总结的时候我会对比oc进行说明,有代码的我会给出相关比对代码。
1. swift简单总结(一)—— 数据简单值和类型转换
2. swift简单总结(二)—— 简单值和控制流
3. swift简单总结(三)—— 循环控制和函数
4. swift简单总结(四)—— 函数和类
5. swift简单总结(五)—— 枚举和结构体
6. swift简单总结(六)—— 协议扩展与泛型
7. swift简单总结(七)—— 数据类型
8. swift简单总结(八)—— 别名、布尔值与元组
9. swift简单总结(九)—— 可选值和断言
10. swift简单总结(十)—— 运算符
11. swift简单总结(十一)—— 字符串和字符
12. swift简单总结(十二)—— 集合类型之数组
13. swift简单总结(十三)—— 集合类型之字典
14. swift简单总结(十四)—— 控制流
15. swift简单总结(十五)—— 控制转移语句
16. swift简单总结(十六)—— 函数
17. swift简单总结(十七)—— 闭包(Closures)
18. swift简单总结(十八)—— 枚举

类和结构体

  类和结构体是人们构建代码所用的一种通用且灵活的构造体。与其他编程语言不同的是,swift并不要求你为自定义类和结构体去创建独立的接口和实现文件,你需要做的就是在一个单一文件中定义一个类或者结构体,系统将会自动生成面向其他代码的外部接口。

下面将从下面几个方向进行讲述

  • 类和结构体对比
  • 结构体和枚举是值类型
  • 类是引用类型
  • 类和结构体的选择
  • 集合collection类型的赋值和复制行为

类和结构体对比

1. 类和结构体的对比

swift中类和结构体有很多共同点,主要是:

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

与结构体相比,类还有如下的功能:

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

注意:结构体总是通过被复制的方式在代码中传递,因此,请不要使用引用计数。

2. 定义

  下面我们看一下类和结构体是如何定义的,习惯上类名和结构体名是以大写字母开头,属性和方法是以小写字母开头,这复合swift的习惯。

下面看一下具体的定义。


class SomeClass {
    //class definition goes here
}

struct SomeStruct {
    //structure definition goes here
}

下面我们接着看定义实例。

struct Resolution {
    var width = 0
    var height = 0
}

class VideoMode{
    var resolution = Resolution()
    var interlaced = false
    var frameRate = 0.0
    var name : String?
}

3. 类和结构体实例

  可以用下边方式进行实例化,结构体和类都使用构造器语法来生成新的实例,构造器语法的最简单形式是在结构体或者类的类型名称后跟随一个空括号。

let someResolution = Resolution()
let someVideoMode = VideoMode()

4. 属性访问

  可以使用点语法,你可以访问实例中所包含的属性,语法规则是:实例名称紧跟属性名。

    let someResolution = Resolution()
    let someVideoMode = VideoMode()
    print(someResolution.width)
    print(someVideoMode.resolution.width)

你可以使用点语法为属性变量赋值。

someVideoMode.resolution.width = 100

  大家可以看点,swift允许使用点语法直接给一个属性赋值,这个比OC要灵活的多了,大家估计还记得OCframe,不可以直接改变其中的成员,要找一个中间变量,改变中间变量的成员,修改以后在赋值回去才可以。这一点swift要灵活的多了。

5. 结构体类型的成员逐一构造器 - Memberwise Initializers for structure Types

  所有结构体都有一个自动生成的成员逐一构造器,用于初始化新结构体实例中成员的属性,新实例中各个属性的初始值可以通过属性的名称传递到成员逐一构造器中,下面看代码。

let resolution = Resolution(width: 1920, height: 1080)

与结构体不同,类实例没有默认的成员逐一构造器。


结构体和枚举是值类型

  值类型被赋予给一个变量,常数或者本身被传递给一个函数的时候,实际上操作的是其的拷贝。其实,在swift中,所有基本类型:整数、浮点数、布尔值、字符值、数组和字典,都是值类型,并且都是以结构体的形式在后台所实现。在swift中,所有的结构体和枚举都是值类型,这意味着他们的实例,以及实例中所包含的任何值类型属性,在代码中传递的时候都会被复制。

let resolution = Resolution(width: 1920, height: 1080)
var cinema = resolution

  在上面的例子中,声明一个常量resolution并给一个初始值,然后又定义了名字为cinema的变量,其值为之前声明的resolution,因为Resolution是一个结构体,所以cinema的值其实是resolution的一个拷贝副本,而不是resolution本身,尽管resolutioncinema有着相同的宽和高,但是在后台中,它们是两个完全不同的实例。

下面看这个例子

class JJSwiftVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        let resolution = Resolution(width: 1920, height: 1080)
        var cinema = resolution
        cinema.width = 2080
        print("cinema = \(cinema)")
        print("resolution = \(resolution)")
    }
}

下面看输出结果

cinema = Resolution(width: 2080, height: 1080)
resolution = Resolution(width: 1920, height: 1080)

  进一步证明了结构体是值类型,在将resolution赋值给cinema的时候,实际上是将resolution中所存储的值进行拷贝,然后将拷贝的数据存储到新的cinema中,结果是两个完全独立的实例碰巧包含有相同的数值。修改其中一个的值,不会影响另外一个的值。

枚举也遵循相同的准则

class JJSwiftVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        var currentDirection = CompassPort.West
        let lastDirection = currentDirection
        currentDirection = .East
        if lastDirection == .West {
            print("The remember direction is still .West")
        }
        else {
            print("The remember direction is still .East")
        }
    }
}

下面看输出结果

The remember direction is still .West

说明枚举也是值类型。


类是引用类型

  与值类型不同,引用类型在被赋予到一个变量、常量或者被传递到一个函数时,操作的是引用,并不是拷贝,因此,引用的是已知存在的实例本身而不是拷贝。

class JJSwiftVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        let resolution = Resolution()
        let mode = VideoMode()
        mode.resolution = resolution
        mode.interlaced = false
        mode.name = "10086"
        mode.frameRate = 25.0
        
        let nextMode = mode
        nextMode.frameRate = 30.0
        print(mode.frameRate)
        print(nextMode.frameRate)
    }
}

下面看输出结果

30.0
30.0

  可见,类是引用类型。还需要注意的是modenextMode被声明为常量,而不是变量,然而你依然可以更改里面的frameRate,因为这两个常量本身不会改变,它们并不存储这个nextMode实例,在后台仅仅是对nextMode的引用,所以,改变的是被引用的基础nextModeframeRate参数,而不改变常量的值。

1. 恒等运算符

  因为类是引用类型,有可能有多个常量和变量在后台同时引用某一个类实例,如果能够判断两个常量或者变量是否引用同一个类实例将会很有帮助,为了这个目的,swift内建了两个恒等运算。

  • 等价于(===)
  • 不等价于(!==)

看下面这个例子。

class JJSwiftVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        let resolution = Resolution()
        let mode = VideoMode()
        mode.resolution = resolution
        mode.interlaced = false
        mode.name = "10086"
        mode.frameRate = 25.0
        
        let nextMode = mode
        nextMode.frameRate = 30.0
        print(mode.frameRate)
        print(nextMode.frameRate)
        
        if mode === nextMode {
            print("They are the same instance !")
        }
        else {
            print("They are not the same instance !")
        }
    }
}

下面看输出结果

30.0
30.0
They are the same instance !

这里还要注意=====的不同:

  • ===表示两个类类型的常量或者变量是否引用同一个类实例。
  • ==表示两个实例的值相等或者相同。

2. 指针

  对于COC,你知道使用指针来引用内存中的地址,一个swift常量或者变量引用一个引用类型的实例与C语言中的指针类似,不同的是并不直接指向内存中的某个地址,而且也不要求你使用星号*来表明你在创见意一个引用,swift中这些引用于其他的常量或者变量的定义方式相同。


类和结构体的选择

  在选择之前要记住,结构体是值类型,类是引用类型,按照通用标准,当符合下面的条件时,请考虑结构体。

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

简单举几个适合结构体的例子。

  • 几何形状的大小
  • 一定范围内的路径
  • 三维坐标系内一点

在所有其他案例汇中,基本都是定义一个类,生成一个它的实例。


集合类型的赋值和拷贝行为

  swift中的字符串String、数组Array和字典Dictionary类型均以结构体的形式实现,这意味着,StringArrayDictionary类型的数据被赋值给新的变量或者常量,或者被传入函数方法中,它们的值会发生拷贝行为(值传递方式)。

  而在OC中字符串NSString、数组NSArray和字典NSDictionary类型均以类的形式出现,这与swift中以值传递的方式是不同的,字符串NSString、数组NSArray和字典NSDictionary在发生赋值或者传入函数方法中时,不会发生值拷贝,而是传递已存在实例的引用。

注意:实际上,在你的代码中,数组字典字符串的拷贝好像确实是在有拷贝行为的地方产生过,然而,在swift后台中,只有确有必要,actural实际拷贝才会被执行,swift管理拷贝以确保最优化的性能,所以你也没有必要去避免赋值以保证最优性能,实际赋值由系统管理优化。

后记

未完,待续~~~

swift简单总结(十九)—— 类和结构体_第1张图片
秦时明月

你可能感兴趣的:(swift简单总结(十九)—— 类和结构体)