// 1.结构体
func test_struct() {
// 在swift标准库中,绝大数公开的类都是结构体,枚举和类只占一小部分
// Bool、Int、Double、String、Array、Dictionary等常见类型都是结构体
struct Date {
var year: Int
var month: Int
var day: Int
var stringDesc: String {
get {
return String(format: "%04d-%02d-%02d", year, month, day)
}
}
}
// 编译器会默认为结构体生成一个初始化器,参数包含所有的存储属性
let date = Date(year: 2019, month: 7, day: 11)
print("Date is \(date)")
print("Datedesc is \(date.stringDesc)")
// 编译器根据情况自动为结构体生成不同的的初始化器
// 具体情况视成员属性而定,宗旨:所有存储属性创建出来都能被初始化
struct Point1 {
var x: Int
var y: Int
// 自动生成(保证x和y能被初始化)
// Point1(x: <#T##Int#>, y: <#T##Int#>)
}
let p1 = Point1(x: 1, y: 1)
struct Point2 {
var x: Int = 0
var y: Int
// 自动生成(保证y能被初始化)
// Point1(x: <#T##Int#>, y: <#T##Int#>)
// Point2(x: <#T##Int#>)
}
let p21 = Point2(x: 2, y: 2)
let p22 = Point2(y: 2)
struct Point3 {
var x: Int = 0
var y: Int = 0
// 自动生成(x和y都已经初始化了,不许要在保证,因此可以生成一下几个构造方法)
// Point3()
// Point3(x: <#T##Int#>, y: <#T##Int#>)
// Point3(x: <#T##Int#>)
// Point3(y: <#T##Int#>)
}
let p31 = Point3()
let p32 = Point3(x: 2, y: 2)
let p33 = Point3(x: 2)
let p34 = Point3(y: 3)
// 当自己定义了初始化函数后,编译器不会再自动生成其它初始化函数
struct Point4 {
var x: Int = 0
var y: Int = 0
// Point4(x: <#T##Int#>, y: <#T##Int#>)
init(x: Int, y: Int) {
self.x = x
self.y = y
}
// 由于自定义了初始化器,以下三个构造器编译器不会生成
// Point4()
// Point4(x: <#T##Int#>)
// Point4(y: <#T##Int#>)
}
let p41 = Point4(x: 2, y: 2)
// 初始化成员值和构造器的本质
/**
事实上,虽然Test1中在定义成员的时候给了初始值,但a和b发生初始化的时机在init方法中
即Test1中会自动生成类似Test2中的init方法,Test1和Test2完全等价
*/
struct Test1 {
var a: Int = 0
var b: Int = 0
}
let t1 = Test1()
struct Test2 {
var a: Int
var b: Int
init() {
self.a = 0
self.b = 0
}
}
let t2 = Test2()
}
test_struct()
// 2.类
func test_class() {
// 类在初始化成员值时的原理和结构体相同,都是在无参init方法中
// 默认情况下,编译器不会帮类生成初始化构造器
/**
class Size1 {
var w: Int
var h: Int
// 注意:该类没有任何构造器
}
*/
/**
class Size2 {
var w = 10
var h: Int
}
*/
// 当且仅当类的所有成员都有初始值的时候,编译器才会为类生成无参构造方法
class Size3 {
var w = 10
var h = 20
}
let s3 = Size3()
// 同结构体,一下两段代码完全等效[Size4 和 Size5 等效]
class Size4 {
var a: Int = 0
var b: Int = 0
}
let s4 = Size4()
class Size5 {
var a: Int
var b: Int
init() {
self.a = 0
self.b = 0
}
}
let s5 = Size5()
}
test_class()
// 3.结构体和类的本质区别
func test_struct_class() {
// (1)结构和枚举:值类型
// 创建对象,在哪里创建对象,就在哪里开辟对象需要的内存空间
// (2)类:引用类型(指针类型)
// 创建对象,对象需要的内存通常开辟堆空间,而在创建的地方使用一个指针指向该堆空间
// 值类型
struct sPoint1 {
var x = 10
var y = 30
}
let sp1 = sPoint1()
/**
sp1 的结构
┏━━━━━━━┓
┃ x(10) ┃
┃ y(30) ┃
┗━━━━━━━┛
如果在函数内部创建sp1,则在栈空间开辟 16个字节
如果在全局区创建sp1,则在数据段开辟 16个字节
如果sp1是类的成员变量,则在堆空间开辟 16个字节
*/
print("sPoint1 sp1 size:\(MemoryLayout.size(ofValue: sp1))")
class cPoint1 {
var x = 10
var y = 30
}
let cp1 = cPoint1()
/**
cp1 的结构
┏━━━━━━━┓
┃ cp1 ┃
┃(指针) ------> 堆空间
┗━━━━━━━┛ ┏━━━━━━━━━━━━━┓
┃ classInfo ┃
┃ retainCount ┃
┃ x(10) ┃
┃ y(30) ┃
┗━━━━━━━━━━━━━┛
这里,cp1是一个指针,同样,cp1可能在栈空间、堆空间、全局区
但是 cp1指向的对象,一定在堆空间
因此cp1占用8个字节,cp1指向的对象占用32个字节
*/
print("cPoint1 cp1 size:\(MemoryLayout.size(ofValue: cp1))")
print("cPoint1 cp1 obj size:\(class_getInstanceSize(type(of: cp1)))")
// (3)值类型的赋值(实际上是深拷贝:Copy On Write)
let sp2 = sp1 // 这里实际上会将sp1的内存拷贝一份到新的sp2空间
var sp3 = sp1 // 同上
// 不过在swift标准库中,为了提升性能,String、Array、Dictionary、Set等采取了Copy On Write技术
// 该技术意思是,只有被拷贝的副本真正需要执行写(修改)操作的时候,才会进行深拷贝操作
// 不过该操作只针对swift标准库类型
// 所以在我们不需要修改类型时,尽量使用let定义,这样编译器直接不会进行深拷贝操作
// 注意:
var sp4 = sPoint1(x: 1, y: 2)
sp4 = sPoint1(x: 3, y: 5)
/**
sp4 的结构
┏━━━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━━┓
┃0x1000000 x(1) ┃ ------> ┃0x1000000 x(3) ┃
┃0x1000008 y(2) ┃ ┃0x1000008 y(5) ┃
┗━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━━┛
//该操作实际上类似于深拷贝,sp4不会开辟新空间,而是值覆盖
*/
// (4)引用类型的赋值(浅拷贝,即拷贝内存地址:指针地址)
let cp2 = cp1
// 该操作只会让cp2拥有和cp1同样的指针地址
// 即两个指针指向同一个对象,虽然cp2拥有cp1相关信息,但并不拥有独立空间
}
test_struct_class()
// 4.let 对值类型和引用类型的区别
func test_let_for_struct_class() {
struct Point {
var x = 1
var y = 1
}
class Size {
var x = 1
var y = 1
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
let p = Point(x: 5, y: 4)
// p.x = 8 // 报错
let s = Size(x: 5, y: 4)
s.x = 8
/** 对比可知
对于let修饰的:
如果是值类型,那么该对象本身和内部成员都不可修改
如果是引用类型,那么指针指向不可修改,但是指向的对象可以修改
可以粗暴的这样理解
对于值类型 p 被 let 修饰,由于p的成员都在let之后,则不可修改
对于引用类型 s 被 let 修饰,s的在let之后,但s指向的对象却在另一个空间,不归let管
*/
}
test_let_for_struct_class()
// 5.嵌套类型和方法
func test_nest_func() {
// 嵌套
struct A {
enum A1 {
case a11, a12, a13, a14
}
enum A2: Int {
case a21 = 2, a22, a23, a24
}
}
var a1 = A.A1.a13
a1 = .a14
// 类、结构体、枚举 都可以定义方法
class Size {
var w = 10
var h = 10
func show(){
print("Size w = \(w), h = \(h)")
}
}
struct Point {
var x = 10
var y = 10
func show(){
print("Point w = \(x), h = \(y)")
}
}
enum TestEnum {
case a1, a2, a3
func show(){
print("A is \(self)")
}
}
let s = Size()
s.show()
let p = Point()
p.show()
let e = TestEnum.a1
e.show()
}
test_nest_func()
认识Swift系列6之结构体和类
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...