在OC中,对属性显示声明为copy或者strong,让我们知道要操作的对象是否为同一个地址。
但是在Swift中,我们通过let、var时,并不能第一时间知道到底是哪种方式。
比如OC中:
@property(nonatomic,strong) NSMutableArray *dataSource;
我们改变dataSource数组里的内容,dataSource的地址不变。
在Swift中会如何呢?
var arr1 = ["a","b","c"]
var arr2 = arr1
arr1.remove(at: 0)
那么此时arr1和arr2的内容相同吗?
如果改变var和let呢?
var arr1 = ["a","b","c"]
let arr2 = arr1
arr1.remove(at: 0)
再或者,arr1和arr2的地址一样吗?
咱们从地址开始分析,首先Swift中如何打印对象的地址呢?Swift语言成长中,波动较大,但目前已趋于稳定。
从Swift4开始,使用
Unmanaged.passUnretained(obj).toOpaque()
之前的let adress = String.init(format: "%p", arr)
和unsafeaddressof
都已无效。
定义一个打印地址的方法:
func printAddress(values:AnyObject...){
for value in values {
print(Unmanaged.passUnretained(value).toOpaque())
}
line()
}
func line(){
print("----------------")
}
单例验证地址
首先从一个单例开始,看是否每次取到的都是同一个地址
final class Single:NSObject{
static let shared = Single()
private override init(){
}
}
var s1 = Single.shared
var s2 = Single.shared
var s3 = Single.shared
printAddress(values: s1 as AnyObject,s2 as AnyObject,s3 as AnyObject)
打印结果:
总结:
多次获取单例对象,得到是同一个地址。
基本类型
var a1 = 5
let b1 = a1
a1 = 8
print(a1,b1)
printAddress(values: a1 as AnyObject,b1 as AnyObject)
let a2 = 5
let b2 = a2
printAddress(values: a2 as AnyObject,b2 as AnyObject)
let a3 = 5
var b3 = a3
b3 = 8
print(a3,b3)
printAddress(values: a3 as AnyObject,b3 as AnyObject)
var a4 = 5
var b4 = a4
a4 = 8
print(a4,b4)
printAddress(values: a4 as AnyObject,b4 as AnyObject)
打印结果:
总结:
- 同一个内容,同一个地址。
- 改变了内容,新的地址。
String
var str10 = "hello"
var str11 = str10
print(str10,str11)
printAddress(values: str10 as AnyObject,str11 as AnyObject)
str10 = "word"
print(str10,str11)
printAddress(values: str10 as AnyObject,str11 as AnyObject)
line()
var str12 = "hello"
printAddress(values: str10 as AnyObject,str11 as AnyObject,str12 as AnyObject)
line()
由于有了上次的规律,这次不再let给let,let给var,var给let三种情况进行验证,而是对改变内容来验证。
总结:
- 同一个内容,同一个地址。
- 改变了内容,新的地址。
需要注意的是,Swift中的String不同于OC中的NSString(继承自NSObject),并不是一个类,而是结构体。
NSString
var nsstr = NSString.init(string: "hello")
let nsstr1 = nsstr
print(nsstr,nsstr1)
printAddress(values: nsstr,nsstr1)
nsstr = "word"
print(nsstr,nsstr1)
printAddress(values: nsstr,nsstr1)
let nsstr2 = NSString.init(string: "hello")
printAddress(values: nsstr,nsstr1,nsstr2)
同理测试NSString在Swift中使用let、var的情况:
总结:
- 同一个内容,同一个地址。
- 改变了内容,新的地址。
Array
先来验证开篇的问题,AViewController中的dataSource数组,传递给BViewController,在BViewController中改变这个数组内容,A中会变吗?
var arr1 = ["a","b","c"]
var arr2 = arr1
print(arr1,arr2)
arr1.remove(at: 0)
print(arr1,arr2)
总结:
改变arr2,并不会影响arr1的内容。
看一下地址的变化吧:
var arr1 = ["a","b","c"]
var arr2 = arr1
print(arr1,arr2)
printAddress(values: arr1 as AnyObject,arr2 as AnyObject)
arr2.remove(at: 0)
print(arr1,arr2)
printAddress(values: arr1 as AnyObject,arr2 as AnyObject)
arr2.append("d")
print(arr1,arr2)
printAddress(values: arr1 as AnyObject,arr2 as AnyObject)
arr1.remove(at: 0)
print(arr1,arr2)
printAddress(values: arr1 as AnyObject,arr2 as AnyObject)
进行了一波骚操作,然后得到了一个我不太明白的地址变化:
额,这个地址变化的我猝不及防,ANYWAY,我们还是能得出这个结论:
总结:
不管你是let给var,还是var给let还是var给var,改变任意一个变量的值,均互不影响。即:地址相互独立。
结构体
var my = MyStruct.init(height: 5)
var my1 = my
my.height = 10
print(my1.height)
结果:5
嗯,看一下你地址
var my = MyStruct.init(height: 5)
var my1 = my
printAddress(values: my as AnyObject,my1 as AnyObject)
my.height = 10
print(my1.height)
printAddress(values: my as AnyObject,my1 as AnyObject)
结果:
0x00007fd827d2f9e0
0x00007fd827d2fa10
5
0x00007fd827d306c0
0x00007fd827d30370
这个...算了,不看了,毕竟我解释不了的东西,拿出来就是坑...
反正!我就是得到这个结论:
总结:互不影响。
Class
额,这个其实不用测了,因为这个肯定是影响的。
class Person {
let name:String
var age:Int
init(name:String,age:Int) {
self.name = name
self.age = age
}
}
let xm = Person.init(name: "xiaoming", age: 15)
let r = xm
printAddress(values: xm,r)
xm.age = 5
print(xm.age,r.age)
printAddress(values: xm,r)
结果是:
不过!类的数组是相互独立的!
常见的就是两个类之间传递数据,那么数组被传递过去即为copy,无法相互影响数据内容。
总结:
改变ps数组的内容,psb不变。
实际问题
所以像是先var一个变量,取出来需要改变的值,那么就无法再改回去了。
举个例子:创建一个人,名字叫晓明,有右手和左手,然后我们想要去掉他的一个手,让他成为杨过。
结果:晓明还是俩手。
我们上面已经知道了,数组是copy的,copy后互不影响的,那咱们试试改名字:
结果:“晓明”成功改为了“黄明”。
是不是就不能让晓明断手,成为杨过了呢?
NO,直接断他的手就行了啊。
👌