Swift基础语法(五)类和结构体的简单认识

Swift基础语法文章汇总

本文简述了结构体和类的基本定义,并且说明他们二者的区别,结构体是值类型,类是引用类型。区别于其他语言,Swift提供的标准库中大部分公开类型都是结构体,而非类。

主要内容:

  1. 结构体
  2. 结构体和类的区别

1、结构体

在Swift标准库中,绝大多数的公开类型都是结构体,而枚举和类只占很小一部分

1.1 常见结构体

比如Bool、Int、Double、String、Array、Dictionary其实都是结构体类型。


结构体类型.png

1.2 结构体的初始化器

初始化器实现:

/*
 1、结构体的初始化器
 注意:初始化器必须保证所有存储属性都完成初始化
 */
struct Point1 {
    var x: Int = 5
    var y: Int
}

//此时都有值
var p11 = Point1(x: 10, y: 10)
//xYou自己的初始值5
var p12 = Point1(y: 10)
//y没值
//var p3 = Point(x:5)
//x、y都没值
//var p4 = Point()

说明:

  1. 所有的结构体都有编译器自动生成的初始化器
  2. 并且编译器会根据存储属性的设置情况提供多个初始化器
  3. 怎样提供初始化器的宗旨是“保证所有成员都有值”

本质:初始化器中给存储属性赋初始值
代码:

struct WYPoint {
    var x: Int = 0
    var y: Int = 0
}
var p = WYPoint()

查看汇编

  1. 执行WYPoint结构体的初始化器
调用初始化器.png
  1. 跳入函数内查看
初始化器赋值.png

说明:

  1. 可以看到对结构体进行初始化时,会调用init()初始化器
  2. 在init初始化器中,会给两个变量赋值,rbp就是结构体的地址值

1.3 自定义结构体

初始化器实现:

/*
 2、自定义初始化器
 */
struct Point2 {
    var x : Int = 0
    var y : Int = 0
    init(x: Int, y: Int) {
        self.x = x
        self.y = y
    }
}
//只有这个初始化器
var p21 = Point2(x: 10, y: 10)
//系统不再提供默认初始化器
//var p22 = Point2(y: 10)
//var p23 = Point2(x:5)
//var p24 = Point2()

说明:

  1. 注意初始化器的定义格式
  2. 我们看到如果提供了自定义的初始化器,默认的初始化器系统将不再提供

1.4 结构体内存结构

代码:

/*
 3、结构体的内存查看
 */
struct Point3 {
    var x: Int = 0
    var y: Int = 0
    var origin: Bool = false
}
print(MemoryLayout<Point3>.size) // 17
print(MemoryLayout<Point3>.stride) // 24
print(MemoryLayout<Point3>.alignment) // 8

说明:

  1. .size得到的是结构体实际使用了内存大小
  2. .stride得到的是结构体的实际占用内存大小
  3. .alignment得到的是当前的对齐方式

2、类

类的定义和结构体是类似的,但是编译器并没有为类自动生成可以传入成员值的初始化器,只有一个空构造。
类默认只有一个空的构造器,但是这个空构造中也必须给成员变量赋值
虽然可以定义存储属性、计算属性、方法、下标,但是真正类的内存中存储的只有存储属性(可以理解为OC的成员变量)

2.1 初始化器

类的初始化器也必须要给所有的存储属性赋值

代码:

/*
 1、类的初始化器
 */
//没有给存储属性赋值,类的定义会报错
//class Point4 {
//    var x: Int
//    var y: Int
//}
//let p41 = Point4()//报错,没有给存储属性赋初始值

//只有空构造
class Point5 {
    var x: Int = 0
    var y: Int = 0
}
let p51 = Point5()//空构造中赋初始值,不报错
//let p52 = Point5(x: 10,y: 20)//默认没有其他构造器
//let p53 = Point5(x: 10)//默认没有其他构造器
//let p54 = Point2(y: 20)//默认没有其他构造器

说明:

  1. 系统只会给类提供空构造,而且空构造必须能够给类的存储属性赋初始值
  2. 在Point4类中,因为没有给x/y设置初始值,所以空构造也是没有的,因为不知道如何赋值
  3. 因此不在的定义中设置初始值,就必须自定义初始化器,而不能用空初始化器
  4. 在Point5类中,有初始值,此时就有空初始化器了
  5. 如果类的所有成员都在定义的时候指定了初始值,编译期会为类生成无参的初始化器
  6. 成员的初始化就在这个初始化器中完成的,虽然没写,但是系统会自动生成并帮我们实现

注意:

  • 在类中的初始化值本质其实是通过构造器来赋值的
  • 类中只会自动生成不传参的空构造器

2.2 反初始化器

反初始化器可以理解为析构器(C++)
代码;

/*
 2、类的反初始化器
 */
class Person {
    var x: Int = 0
    var y: Int = 0
    deinit {
        print("WY:Perosn对象销毁了")
    }
}

func testInit() -> Void {
    var person = Person()
}

testInit()//WY:Perosn对象销毁了

//继承关系中的反初始化器
class Student : Person {
    deinit {
        print("WY:Student对象销毁了")
    }
}
func testInit2() -> Void {
    var student = Student()
}
//WY:Student对象销毁了
//WY:Perosn对象销毁了
testInit2()

说明:

  1. 定义方式和析构器一样,只是名字不一样
  2. 所用也是销毁对象
  3. deinit不接受任何参数,不能写(),没有返回值,不能自行调用,必须系统调用
  4. 父类的deinit能被子类继承,如果之类没有反初始化器,会直接调用父类的反初始化器
  5. 子类的deinit调用完毕后会调用父类的deinit

2.3 类的内存分配和占用

这里和OC是一样的,占用内存大小为8字节对齐,分配内存大小为16字节对齐
详情可以查看我的另一篇博客苹果的内存对齐原理
代码:

//类的内存大小分析
func testInstanceSize() {
    class Point {
        var x = 11//8
        var test = true//1
        var y = 22//8
    }//33、40、48
    
    let p = Point()
    print(class_getInstanceSize(type(of: p)))//40 print(class_getInstanceSize(Point.self))
    print(Mems.size(ofRef: p))//48
}
testInstanceSize()

说明:

  1. 对象实际使用内存大小为33(8*2+8+1+8)(对象本身会有两个属性,分别是类信息和引用计数)
  2. 占用内存大小为8字节对齐,所以对象实际占用内存大小为40个字节
  3. 系统分配内存大小为16字节对齐,所以对象分配大小为48个字节

3、区别

本质区别在于结构体是值类型,类是引用类型。

区别:

  1. 结构体是值类型,类是引用类型
  2. 类的实体即对象会存储在堆中,结构体的实例存储的地方取决于定义在哪里
    1. 比如定义在函数中,那么就在栈中
    2. 定义在类中,就在堆中
    3. 定义在全局区,那么就在全局区
    4. 结构体定义在类的方法中,也存储在函数栈中
  3. 结构体的拷贝默认是浅拷贝,对象的拷贝是深拷贝

Swift的引用类型和值类型的区别在C++、OC、Java的概念都是一样的,有一定编码基础的同学肯定都接触过,便不在此赘述了

注意:
在Swift标准库中,为了提升性能,String、Array、Dictionary、Set当不出现写入修改时,是浅拷贝,如果是会出现写入的情况则是深拷贝

  • 比如如果是let赋值就不会深拷贝
  • 比如在编译时发现后续不会出现修改值的情况就不会深拷贝
  • 注意只有标准库才会这样的
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容