美文网首页
swift语法记录之结构体和类

swift语法记录之结构体和类

作者: LiuffSunny | 来源:发表于2020-04-21 23:31 被阅读0次

结构体


多个初始化器:一个原则保证所有成员都有初始值



// 一旦在定义结构时,自定义了结构体初始化器,编译器就不会再帮他自动生成其他初始化器
struct Point {
    var x: Int = 0
    var y: Int = 0
    init(x: Int,y: Int) { // init构造器不用写func 不用写函数返回值是一种特殊的写法
        self.x = x;
        self.y = y
    }
}
var p = Point(x: 10, y: 20)
var p1 = Point(x: 10)// 报错
var p2 = Point(y: 20)// 报错
var p3 = Point()// 报错

查看初始化器的本质(汇编)

//第一种
func testfunc (){
    struct Point {
        var x: Int = 5
        var y: Int = 6
    }
    var p = Point()
}
testfunc()

image.png
// 第二种
func testfunc (){
    struct Point {
        var x: Int
        var y: Int
        init() {
            x = 5
            y = 6
        }
    }
    var p = Point()
    print(MemoryLayout<Point>.size) // 16
    print(MemoryLayout<Point>.stride) // 16
    print(MemoryLayout<Point>.alignment) //8
}
testfunc()

第一种和第二种对比发现,不仅方法一致汇编指令一致,甚至连内存地址也是一致的所以这两种是完全等价的.构造器的实现,就是我们所写的这样.

结构体的内存大小

func testfunc (){
    struct Point {
        var x: Int = 1
        var y: Int = 2
        var z: Bool = true
    }
    var p = Point()
    print(MemoryLayout<Point>.size) // 17
    print(MemoryLayout<Point>.stride) // 24
    print(MemoryLayout<Point>.alignment) //8
}
testfunc()


// 如果所有成员都有初始值,编译器会为类生成一个无参的初始化器
// 但是没有初始值的时候,无参的初始化器就不能使用


类和结构体本质区别

func testClassAndStruct() {
    class Size {
        var width: Int = 3
        var height: Int = 4
    }
    struct Point {
        var x: Int = 10
        var y: Int = 20
    }
    var point = Point()
//    var size = Size()
}

可以观察出结构体Point只是callq了init构造方法,并没有任何molloc申请堆空间的地方



下面观察类Size:



// 经过不断的si往下查找可以发现如图

// 最终调用系统级别的分配堆空间的函数



// 继续进入

综上所述:结构体是不需要分配堆空间的,而类是需要系统分配堆空间的

查看类实例和结构体变量的内存

func testClassAndStruct() {
    class Size {
        var width: Int = 3
        var height: Int = 4
    }
    struct Point {
        var x: Int = 10
        var y: Int = 20
    }
    var size = Size()
    var point = Point()
    print("变量size的内存地址:\(Mems.ptr(ofVal: &size))")
    print("变量size的内存数据\(Mems.memStr(ofVal: &size))") //打印出来是一个地址,指向另一块堆空间
    print("size所指向内存的地址:\(Mems.ptr(ofRef: size))")//获取变量所指向的内存的内存地址
    print("size所指向内存的地址的内容:\(Mems.memStr(ofRef: size))")
    print("---------------------")
    print("变量point的内存地址:\(Mems.ptr(ofVal: &point))")
    print("变量point的内存数据\(Mems.memStr(ofVal: &point))")
//变量size的内存地址:0x00007ffeefbff0b8
//变量size的内存数据0x0000000100406030
//size所指向内存的地址:0x0000000100406030
//size所指向内存的地址的内容:0x000000010000b340 0x0000000200000002 0x0000000000000003 0x0000000000000004
//---------------------
//变量point的内存地址:0x00007ffeefbff0c0
//变量point的内存数据0x000000000000000a 0x0000000000000014
// 我们分别可以找到 3 4 10 20 在哪里,
// 值得注意的是变量size占8个字节,而其地址指向的内存空间占32个字节
// 虽然size创建比point要晚,但是变量size的内存地址:0x00007ffeefbff0b8 要比变量point的内存地址:0x00007ffeefbff0c0 靠前一些相差16个字节 刚好是变量point的内存长度
}
testClassAndStruct()

注意:
结构体(值类型)的内存取决于结构体变量放在哪里
1.如果放在函数里,就在栈空间
2.如果放在上面,就是数据区,因为这时候是全局变量
3.放在类里面,就是在堆空间
类(引用类型)的内存放在哪里
1.size指针变量取决于放在哪里
2.类对象(实例)永远是在堆空间

func testClassAndStruct() {
    class Size {
        var width: Int = 3
        var height: Int = 4
        func test() {
            var p = Point()// 此时结构体还是在栈空间(函数不管在哪里,栈空间是不变的,在类里面和全局函数都是一样的)
        }
    }
    struct Point {
        var x: Int = 10
        var y: Int = 20
    }
    var point = Point()
    var size = Size()
}

值类型 汇编代码分析

深拷贝



寄存器的兼容性我们知道%edi存储在%rdi里,%esi存储在%rsi里



init函数里的操作是把%rdi给了%rax,%rsi给了%rdx

相关文章

网友评论

      本文标题:swift语法记录之结构体和类

      本文链接:https://www.haomeiwen.com/subject/hfodihtx.html