Swift汇编分析inout关键字

因为inout关键字比较简单,因此该文章篇幅相对比较短小。
我们直到在swiftinout通常用来在函数内修改外部变量使用。那么其实我们也很容易联想到在函数内去修改class对象的某个属性,修改完成后我们在函数外部去访问该属性即是最新的值。
但如果我们需要修改的是一个局部变量或者我们需要修改的变量是一个私有变量,该变量并未声明未public那么此时我们在另一个类中需要修改其值时就比较麻烦了。那么此时我们可以通过inout来实现,这样在不暴露私有变量的情况下即可走相同的逻辑。

class A {
    private var a: Int = 1
    
    func start() {
        B.test(&a)
    }
    
}

class B {
    static func test(_ num: inout Int) {
        num = 20
    }
}

其实通过之前的汇编分析我们大致也可以直到inout本质上应该是将变量对应的地址传入到了函数中,从而修改变量的值。 举个:

var age = 10
func test(_ num: inout Int) {
    num = 20
}
test(&age)

此时断点在test(&age)处,进入到汇编代码中。

image.png

可以看到在调用函数前往rdi中写入的是地址信息,而rdi常用作传递函数参数。这里就不多赘述了,相信根据前面的文章理解这里相对来说是很容易的。

下面我们主要来探究一下属性的inout使用

struct Test {
    var a: Int
    var b: Int {
        willSet {
            print("willset")
        }
        didSet {
            print("didset")
        }
    }
    var c: Int {
        get {
            return a * b
        }
        set {
            b = a + 1
        }
    }
}
func test(_ num: inout Int) {
    num = 20
}
let p = Test(a: 10, b: 20)
test(&p.a)

这里我们可以直接得到结论这边函数传入的就是属性a的地址。

image.png

我们可以看到第15行的说明信息已经是很名曲额的将对象p的地址放入到了rdi中也就是将属性a的地址(注意这里的对象是个结构体)传入到了函数中。

此时我们再将函数调用改为test(&p.c),也就是重写属性的gettersetter方法时。同样直接看汇编。

image.png

直接看第182124行,可以看到现执行getter获取到数据后并保存在一个地址中,然后调用test函数时将该地址传入,后续调用setter方法时在传入该地址。

再去通过汇编看属性观察器的实现其实也是大同小异,不同点则是在函数调用完成后再去调用属性的setter方法,从而触发属性观察器的方法。

你可能感兴趣的:(Swift汇编分析inout关键字)