Swift结构体和类

最近在学习,顺便总结和记录一下

结构体和类

要说结构体和类就需要先说说值类型和引用类型了

Swift的类型分为值类型和引用类型两种

  • 值类型: 在传递和赋值时进行复制,如struct,enum。所有内建类型(包括Int,Bool,String, Array, Dictionary)(OC和Swift区别之一)
  • 引用类型: 只会使用引用对象的一个“指向” ,如class

类与结构体的主要相同点

  • 定义属性用于存储值。
  • 定义函数以提供功能。
  • 定义下标,以便用下标语法来访问它们的值。
  • 通过扩展来扩展它们的默认实现。
  • 利用协议来完成特定标准功能。

类与结构体的主要不同点

  • 类:引用类型。 结构体: 值类型,在设计结构体时,我们可以要求编译器保证不可变性。
  • 内存的管理方式有所不同,类的实例只能通过引用来间接地访问。类能有很多个持有者.需要自己管理其引用计数、引用值得变化。 结构体可以被直接持有及访问,不会被引用,但是会被复制。也就是说,结构体的持有者是唯一的。
  • 类:可以继承,结构体(以及枚举): 不能被继承的。

结构体的一些说明

  • 结构体只有一个持有者,所以它不可能造成引用循环。而对于类和函数这样的引用类型,我们需要特别小心,避免造成引用循环的问题。
  • 值总是需要复制这件事情听来可能有点低效,不过,编译器可以帮助我们进行优化,以避免很 多不必要的复制操作。因为结构体非常基础和简单,所以这是可能的。结构体复制的时候发生 的是按照字节进行的浅复制。除非结构体中含有类,否则复制时都不需要考虑其中属性的引用 计数。当使用 let 来声明结构体时,编译器可以确定之后这个结构体的任何一个字节都不会被改变。
  • 如果一个结构体只由其他结构体组成,那编译器可以确保不可变性。同样地,当使用结构体时,编译器也可以生成非常快的代码。举个例子,对一个只含有结构体的数组进行操作的效率,通常要比对一个含有对象的数组进行操作的效率高得多。这是因为结构体通常要更直接:值是直接存储在数组的内存中的。而对象的数组中包含的只是对象的引用。最后,在很多情况下,编译器可以将结构体放到栈上,而不用放在堆里。

几个相关的名词

值类型

每个实例都保留了一分独有的数据拷贝,一般以结构体 (struct)、枚举(enum) 或者元组(tuple)的形式出现。

值语义

结构体只有一个持有者。比如,当我们将结构体变量传递给一个函数时,函数将接收到结构体的复制,它也只能改变它自己的这份复制。这叫做值语义,有时候也被叫做 复制语义。

引用类型

每个实例共享同一份数据来源,一般以类(class)的形式出现。

引用语义

而对于对象来说,它们是通过传递引用来工作的,因此类对象会拥有很多持有者, 这被叫做引用语义

下面用代码来验证一下值类型和引用类型

首先定义一个打印内存地址的函数

// 打印对象内存地址
func printAddress(values: AnyObject...) {
    for value in values {
      print(Unmanaged.passUnretained(value).toOpaque())
    }
    print("-----------------------------------------")
}

然后定义一个类和一个结构体

class ObjectTest: NSObject {
    var t1 = 0
}

struct StructTest {
    var t1 = 0
}

给类和结构体分别赋值,打印下结果

let objectTest = ObjectTest()
let objectTest1 = objectTest
objectTest1.t1 = 1
print(objectTest.t1)
print(objectTest1.t1)
let structTest = StructTest(t1: 0)
var structTest1 = structTest
structTest1.t1 = 100
print(structTest.t1)
print(structTest1.t1)
1
1
0
100

给其中一个类objectTest1的t1赋值,然后objectTest的t1随之发生改变,但是结构体structTest1只改变了当前自己的t1,而structTest的t1并没有发生改变。上面说了类和结构体分别是引用类型和值类型,也就是说引用类型和值类型对应发生上面的情况,值类型每个实例保留了一分独有的数据拷贝,而每个实例共享同一份数据来源

验证, 打印结果

printAddress(values: objectTest, objectTest1)
printAddress(values: structTest as AnyObject, structTest1 as AnyObject)
0x000060400001be60
0x000060400001be60
-----------------------------------------
0x0000604000446000
0x0000604000446030
-----------------------------------------

结论

值类型复制的时候,两者的内存地址并不一样。相当于创造了一个完全独立的实例,这个实例保有属于自己的独有数据,数据不会受到其他实例的数据变化影响。值类型就好像身份证复印件一样,复印出来之后,修改原件上面的内容,复印件上的内容不会变。

引用类型复制的时候,因为两者的内存地址是一样的。相当于默默地创造了一个共享的实例分身,两者是共用一套数据。因此修改其中任何一个实例的数据,也会影响到另外那个。

你可能感兴趣的:(Swift结构体和类)