swift4 不同类型拷贝研究

2018-05-23  本文已影响17人  AppleTTT

最近在做内存优化的时候,发现了一些东西,记录一下;
我们经常会使用数组去存储数据,然后再控制器中使用,但是当我们共享数据的时候,我们经常会直接使用 = 操作来进行 赋值,这样的过程是一个深拷贝的过程,先有如下代码:

class Tree: NSObject {
    var name: String = "T"
    init(name: String) {
        self.name = name
    }
    
    override var description: String {
        return name
    }
}

class AAA {
    var arr: [Tree] = []
}

struct MMM {
    var t: Tree
    var description: String {
        return t.name
    }
}

func test() {

    let t1 = Tree.init(name: "1")
    let t2 = Tree.init(name: "2")
    let t3 = Tree.init(name: "3")
    
    let a = AAA.init()
    let b = a

    a.arr = [t1, t2, t3]
    print(a.arr,"---", b.arr)
    
    let t4 = Tree.init(name: "4")
    a.arr.append(t4)
    print(a.arr,"+++", b.arr)
    
    let t5 = Tree.init(name: name)
    let t6 = t5
    print("t5", address(of: t5))
    print("t6", address(of: t6))
    print("t5.name", address(of: t5.name),"t6.name", address(of: t6.name))
    t5.name = "newName"
    print("t5.newName", t5.name, address(of: t5.name),"t6.name", t6.name, address(of: t6.name))
    
    var m1 = MMM.init(t: t1)
    var m2 = MMM.init(t: t2)
    var m3 = MMM.init(t: t3)

    
    var mArr = [m1, m2, m3]
    var nArr = mArr
    var m4 = MMM.init(t: t4)
    nArr.append(m4)
    mArr.append(m1)
    
    print("pppppp",  mArr, nArr)
    
    print("mArr", address(of: &mArr))
    print("nArr", address(of: &nArr))

    print("mArr[0]", address(of: &mArr[0]))
    print("mArr[1]", address(of: &mArr[1]))
    print("mArr[2]", address(of: &mArr[2]))
    print("mArr[3]", address(of: &mArr[3]))
    
    print("nArr[0]", address(of: &nArr[0]))
    print("nArr[1]", address(of: &nArr[1]))
    print("nArr[2]", address(of: &nArr[2]))
    print("nArr[3]", address(of: &nArr[3]))
    
    print("m1", address(of: &m1))
    print("m2", address(of: &m2))
    print("m3", address(of: &m3))
    print("m4", address(of: &m4))
    
    print("mArr[0].t", address(of: &mArr[0].t))
    print("mArr[1].t", address(of: &mArr[1].t))
    print("mArr[2].t", address(of: &mArr[2].t))
    print("mArr[3].t", address(of: &mArr[3].t))
    
    print("nArr[0].t", address(of: &nArr[0].t))
    print("nArr[1].t", address(of: &nArr[1].t))
    print("nArr[2].t", address(of: &nArr[2].t))
    print("nArr[3].t", address(of: &nArr[3].t))
    
}

func address<T: AnyObject>(of object: T) -> String {
    let addr = unsafeBitCast(object, to: Int.self)
    return String(format: "%p", addr)
}
    
func address(of object: UnsafeRawPointer) -> String {
    let addr = Int(bitPattern: object)
    return String(format: "%p", addr)
}

记录结果如下:

[1, 2, 3] --- [1, 2, 3]
[1, 2, 3, 4] +++ [1, 2, 3, 4]
t5 0x1d022e400
t6 0x1d022e400
t5.name 0x1d04598e0 t6.name 0x1d04598e0
t5.newName newName 0x1d04598e0 t6.name newName 0x1d04598e0
pppppp [AAA.MMM(t: 1), AAA.MMM(t: 2), AAA.MMM(t: 3), AAA.MMM(t: 1)] [AAA.MMM(t: 1), AAA.MMM(t: 2), AAA.MMM(t: 3), AAA.MMM(t: 4)]
mArr 0x1d00948e0
nArr 0x1d0094890
mArr[0] 0x16faed4f8
mArr[1] 0x16faed4f0
mArr[2] 0x16faed4e8
mArr[3] 0x16faed4e0
nArr[0] 0x16faed4d8
nArr[1] 0x16faed4d0
nArr[2] 0x16faed4c8
nArr[3] 0x16faed4c0
m1 0x16faed558
m2 0x16faed550
m3 0x16faed548
m4 0x16faed530
mArr[0].t 0x16faed4b8
mArr[1].t 0x16faed4b0
mArr[2].t 0x16faed4a8
mArr[3].t 0x16faed4a0
nArr[0].t 0x16faed498
nArr[1].t 0x16faed490
nArr[2].t 0x16faed488
nArr[3].t 0x16faed480

总结:

1. 数组赋值是深拷贝的过程,因为是值类型;类是浅拷贝,因为类是引用类型;
2. 当我们在类里面有值类型的变量的时候,进行拷贝,拷贝的两个对象(t5 和 t6)的地址以及值类型变量(t5.name 和 t6.name)的地址都是一样的,如果改变一个对象的值类型变量,两个对象(t5.name 和 t6.name)的都会被改变;
3. 值类型有值类型的变量的时候,复制是深复制,mArr 还有 nArr 以及其数组内的内容都不一样

此次获取地址来自喵神的 gist
自己之前找的打印地址的方法都不对,在 swift4 中使用此法可以正确打印地址

上一篇下一篇

猜你喜欢

热点阅读