目录
结构体
在 Swift 标准库中,绝大多数的公开类型都是结构体,而枚举和类只占很小一部分
比如Bool、Int、Double、 String、Array、Dictionary等常见类型都是结构体
struct Date {
var year: Int
var month: Int
var day: Int
}
var date = Date(year: 2019, month: 6, day: 23)
所有的结构体都有一个编译器自动生成的初始化器(initializer,初始化方法、构造器、构造方法)
在第6行调用的,可以传入所有成员值,用以初始化所有成员(存储属性,Stored Property)
编译器会根据情况,可能会为结构体生成多个初始化器,宗旨是:保证所有成员都有初始值
一、系统初始化方法
func structPractice(){
//1、系统自动生成的初始化方法
do{
print("----------1---------")
struct Point {
var x:Int
var y:Int
}
// let p0 = Point() //报错,没有该方法
// let p1 = Point(x:1) //报错,没有该方法
// let p2 = Point(y:2) //报错,没有该方法
let p3 = Point(x:1,y:2) //系统只生成了该方法 Point(x: 1, y: 2)
print(p3)
}
//2、系统自动生成的初始化方法
do{
print("----------2---------")
struct Point {
var x:Int = 0
var y:Int = 0
}
let p = Point()
print(p)//Point(x: 0, y: 0)
let p1 = Point(x:1)
print(p1)//Point(x: 1, y: 0)
let p2 = Point(y:2)
print(p2)//Point(x: 0, y: 2)
let p3 = Point(x: 1, y: 2)
print(p3)//Point(x: 1, y: 2)
}
//3、内存占用
do{
print("----------3---------")
struct Point {
var x:Int
var y:Int
}
var p = Point(x: 1, y: 2)
//内存占用
print(MemoryLayout.size(ofValue: p))//16
print(MemoryLayout.stride(ofValue: p))//16
print(MemoryLayout.alignment(ofValue: p))//8
print(Mems.ptr(ofVal: &p)) //变量地址 0x00007ffeefbff3b0
print(Mems.memStr(ofVal: &p)) //变量内容 0x0000000000000001 0x0000000000000002
}
}
二、自定义初始化方法
func structPractice2(){
//1、自定义初始化方法
//一旦在定义结构体时自定义了初始化器,编译器就不会再帮它自动生成其他初始化器
do{
print("------------1------------")
struct Point {
var x:Int
var y:Int
init(){
x = 0
y = 0
}
init(x:Int) {
self.x = x
self.y = 0
}
init(y:Int) {
self.x = 0
self.y = y
}
init(x:Int,y:Int) {
self.x = x
self.y = y
}
}
let p = Point()
print(p)//Point(x: 0, y: 0)
let p1 = Point(x:1)
print(p1)//Point(x: 1, y: 0)
let p2 = Point(y:2)
print(p2)//Point(x: 0, y: 2)
let p3 = Point(x: 1, y: 2)
print(p3)//Point(x: 1, y: 2)
}
//2、自定义初始化方法
do{
print("------------2------------")
struct Point{
var x:Int
var y:Int
init(x:Int=0,y:Int = 0){
self.x = x
self.y = y
}
}
let p = Point()
let p1 = Point(x:1)
let p2 = Point(y:2)
let p3 = Point(x:1,y:2)
print(p,p1,p2,p3,separator:"\n")
}
//3、下面代码能编译通过吗
do{
print("------------4------------")
//可选项默认值为nil,所以可以编译通过
struct Point {
var x:Int?
var y:Int?
}
let p = Point() //可编译
let p1 = Point(x:1) //可编译
let p2 = Point(y:2) //可编译
let p3 = Point(x: 1, y: 2)
print(p,p1,p2,p3,separator:"\n")
}
//4、自定义初始化方法
do{
struct Point {
var x:Int?
var y:Int?
init(x:Int=0,y:Int=0) {
self.x = x
self.y = y
}
}
}
}
类
类的定义和结构体类似,但编译器并没有为类自动生成可以传入成员值的初始化器
如果类的所有成员都在定义的时候指定了初始值,编译器会为类生成无参的初始化器
成员的初始化是在这个初始化器中完成的
func classPractice() {
//1、不会生成初始化方法
do{
//报错,没有初始化方法
// class Point {
// var x:Int
// var y:Int
// }
// let p = Point()
}
//2、只会生成无参的初始化方法
do{
print("----------2-----------")
class Point {
var x:Int = 0
var y:Int = 0
}
let p = Point()
// let p1 = Point(x:1)
// let p2 = Point(y:2)
// let p3 = Point(x:1,y:2)
print(p.x,p.y)//0
}
//3、自定义初始化方法(等同于上边)
do{
print("----------3-----------")
class Point {
var x:Int
var y:Int
init() {
x = 0
y = 0
}
}
let p = Point()
print(p.x,p.y)
}
//4、自定义初始化方法
do{
print("----------4-----------")
class Point {
var x:Int
var y:Int
init(x:Int=0,y:Int=0) {
self.x = x
self.y = y
}
}
let p = Point(x: 1, y: 2)
print(p.x,p.y)
}
}
结构体和类的本质区别
一、区别
结构体是值类型(枚举也是值类型),类是引用类型(指针类型)
func structAndClassCompare() {
//1、结构体是值类型
do{
print("----------1---------")
struct Point{
var x = 10
var y = 20
}
var p = Point()
//p变量的地址 0x00007ffeefbff510
//p变量的内容 0x000000000000000a 0x0000000000000014
print("p变量的地址",Mems.ptr(ofVal: &p))
print("p变量的内容",Mems.memStr(ofVal: &p))
}
//2、类是引用类型
do{
print("---------2-----------")
class Size{
var width = 10
var height = 20
}
var s = Size()
//s变量的地址 0x00007ffeefbff508
//s变量的内容 0x0000000100545cf0
//s所指向的内存地址 0x0000000100545cf0
//s所指向的内存大小 32
//s所指向的内存内容 0x000000010000ac88 0x0000000200000002 0x000000000000000a 0x0000000000000014
print("s变量的地址",Mems.ptr(ofVal: &s))
print("s变量的内容",Mems.memStr(ofVal: &s))
print("s所指向的内存地址",Mems.ptr(ofRef: s))
print("s所指向的内存大小",Mems.size(ofRef: s))
print("s所指向的内存内容",Mems.memStr(ofRef: s))
}
}
二、值类型
值类型赋值给var、let或者给函数传参,是直接将所有内容拷贝一份
类似于对文件进行copy、paste操作,产生了全新的文件副本。属于深拷贝(deep copy)
struct Point {
var x:Int
var y:Int
}
func test (){
let p1 = Point(x: 10, y: 20)
let p2 = p1
}
var p1 = Point(x: 10, y: 20)
p1 = Point(x: 11, y: 21)
三、引用类型
引用赋值给var、let或者给函数传参,是将内存地址拷贝一份
类似于制作一个文件的替身(快捷方式、链接),指向的是同一个文件。属于浅拷贝(shallow copy)
class Size {
var width:Int
var height:Int
init(width:Int,height:Int) {
self.width = width
self.height = height
}
}
func test () {
var s1 = Size(width: 10, height: 20)
var s2 = s1
}
引用类型的赋值操作
四、结构体内存分析
func memoryAnalyForStruct() {
//1、结构体内存分布
struct Point{
// 内存对齐如下: 偏移量 大小
var x:Int // 0 8
var b1:Bool // 9 1
var b2:Bool // 10 1
var y:Int // 16 8
}
var p = Point(x: 10, b1: true, b2: false, y: 20)
print(MemoryLayout.size(ofValue: p))//24
print(MemoryLayout.stride(ofValue: p))//24
print(MemoryLayout.alignment(ofValue: p))//8
print(Mems.ptr(ofVal: &p))//0x00007ffeefbff510
print(Mems.memStr(ofVal: &p))//0x000000000000000a 0x0000000000000001 0x0000000000000014
/**
以上分析满足内存对齐条件:
一、结构体变量中成员的偏移量必须是成员大小的整数倍(0被认为是任何数的整数倍)
二、结构体大小必须是所有成员大小的整数倍。
*/
//2、结构体的内存分布
struct Point2 {
var x:Int
var b1:Bool
var b2:Bool
var y:Int
init(x:Int,b1:Bool,b2:Bool,y:Int) {
self.x = x
self.b1 = b1
self.b2 = b2
self.y = y
}
func pointTest(){
print("pointTest")
}
}
var p2 = Point2(x: 10, b1: true, b2: true, y: 20)
p2.pointTest()
print(MemoryLayout.size(ofValue: p2))//24
print(MemoryLayout.stride(ofValue: p2))//24
print(MemoryLayout.alignment(ofValue: p2))//8
print(Mems.ptr(ofVal: &p2))//0x00007ffeefbff510
print(Mems.memStr(ofVal: &p2))//0x000000000000000a 0x0000000000000101 0x0000000000000014
/**
init 函数
结构体内定义的 pointTest函数
代码存在于 代码段 并不占用结构体的内存空间
*/
print("end")
}
五、类的内存分析
func memoryAnalyForClass() {
class Size{
//类的前面有 16个字节 前8字节存储一个地址 指向类信息 第二个8字节存储引用计数
var width:Int//8
var b1:Bool//1
var b2:Bool//1
var height:Int//8
init(width:Int,b1:Bool,b2:Bool,height:Int) {
self.width = width
self.b1 = b1
self.b2 = b2
self.height = height
}
}
var s = Size(width: 10, b1: true, b2: true, height: 20)
print(MemoryLayout.size(ofValue: s))//8
print(MemoryLayout.stride(ofValue: s))//8
print(MemoryLayout.alignment(ofValue: s))//8
print(Mems.ptr(ofVal: &s))//0x00007ffeefbff520
print(Mems.memStr(ofVal: &s))//0x0000000100514810
print(class_getInstanceSize(Size.self))//40 内存对齐后 需要的空间
print(class_getInstanceSize(type(of: s)))//作用同上
print(Mems.size(ofRef: s))//48 malloc 堆空间的内存申请需要是16的倍数
print(Mems.ptr(ofRef: s))//0x0000000100514810
print(Mems.memStr(ofRef: s))//0x000000010000e060 0x0000000200000002 0x000000000000000a 0x0000000000000101 0x0000000000000014 0x0002000000000000
print("end")
}
行者常至,为者常成!