Swift 闭包一些性质的探究

func editInside(string firstString: inout String) -> (()->String, ()->String) {

    firstString = "Modified in editInside"
    withUnsafePointer(to: &firstString, {print("In EditeInSide address \($0)")})

    func edit2()->String {
        firstString = "Modified in edit2"
        withUnsafePointer(to: &firstString, {print("In Edit2 address \($0)")})

        return firstString
    }

    func edit3()->String {
        firstString = "Modified in edit3"
        withUnsafePointer(to: &firstString, {print("In Edit3 address \($0)")})
        return firstString
    }

    return (edit2, edit3)
}

var str333 = "outside"  
withUnsafePointer(to: &str333, {print("In outside address \($0)")})

var (firFuc, secFun) = editInside(string: &str333)

print(firFuc())  
print(secFun())  
print(str333)  

输出结果:

In outside address 0x000000011424fc48 In EditeInSide address 0x000061800005a9b0
In Edit2 address 0x000061800005a9b0
Modified in edit2
In Edit3 address 0x000061800005a9b0
Modified in edit3
Modified in editInside

第一行是 str333 初始的变量地址,第二行是 editInsidestr333 的地址。可以看出虽然是 inout 类型的参数,但是在函数内部也只是 copy 了一份,不是原本的值。

接着后面两行打印了 str33 分别在两个函数里的地址以及返回的内容。可以看到,这个变量和外层的函数是一个地址,可以判断出是在闭包里保留了一份对变量的引用,其内容也发生了改变。

最后打印了外部的 str333 ,可以看出,内容并没有被内部的两个函数改变。可以推测出,inout 参数是在内部被改变后再返回给原始值。

如果代码修改成这个样子:

func editInside(string firstString: inout String) -> (()->String, ()->String) {

    firstString = "Modified in editInside"
    withUnsafePointer(to: &firstString, {print("In EditeInSide address \($0)")})

    func edit2()->String {
        withUnsafePointer(to: &firstString, {print("In Edit2 address \($0)")})
        return firstString
    }

    func edit3()->String {
        withUnsafePointer(to: &firstString, {print("In Edit3 address \($0)")})
        return firstString
    }

    firstString = "Modified after"

    return (edit2, edit3)
}

var str333 = "outside"  
withUnsafePointer(to: &str333, {print("In outside address \($0)")})

var (firFuc, secFun) = editInside(string: &str333)

print(firFuc())  
print(secFun())  
print(str333)  

输出结果变成了:

In outside address 0x0000000115c06c48 In EditeInSide address 0x0000600000058e50
In Edit2 address 0x0000600000058e50
Modified after
In Edit3 address 0x0000600000058e50
Modified after
Modified after

可以看出即使在闭包定以后对值进行修改,在闭包里也可以发生改变。因为闭包里存的是一份引用。假如这种情况下在闭包对这个值再次进行了改变。外部传入的参数本身也只会变成 「Modified after」。因为在内部返回的两个函数执行时,外部函数早就已经执行完毕。inout 参数会在函数执行结束后将值写会原参数。