iOS copy和mutableCopy 整理

copy 和 mutableCopy 你真的理解吗?最近发现很多面试者基本都不能很好地回答这个问题。所以整理一下。

copy和mutableCopy的概念:

copy 浅拷贝,不拷贝对象本身,仅仅是拷贝指向对象的指针。

    NSString *str1 = @"str1";
    NSString *str2 = [str1 copy]; NSLog(@"\nstr1 = %@ str1P = %p \n str2 = %@ str2P = %p", str1, str1, str2, str2); /*输出结果,可以得出下图结论 str1 = str1 str1P = 0x104d75180 str2 = str1 str2P = 0x104d75180 */ 
 
copy网络图解.png

mutableCopy 深拷贝,是直接拷贝整个对象内存到另一块内存中。

    NSMutableString *mStr1 = [@"123" mutableCopy]; NSMutableString *mStr2 = [mStr1 mutableCopy]; NSLog(@"\n mStr1 = %@ mStr1P = %p \n mStr2 = %@ mStr2P = %p", mStr1, mStr1, mStr2, mStr2); /*输出结果,可以得出下图结论 mStr1 = 123 mStr1P = 0x6000004460c0 mStr2 = 123 mStr2P = 0x600000446420 */ 
 
mutableCopy网络图解.png

大部分人可能理解到这里就结束了。
当继续往下提问,如果是浅拷贝,改变str1的值,str2的值会变化吗?

问题1:上面浅拷贝的情况下,改变str1的值,str2的值会变化吗?

大部分人会不假思索的回答,因为str1 和 str2 指向同一个内存空间,str1变化,str2的值也会变化。

分析的很有道理,老铁看似没毛病毛病!

但是copy还有它的特点:

  • 修改源对象的属性和行为,不会影响副本对象
  • 修改副本对象的属性和行为,不会影响源对象

我们来试验一下:

    NSString *str1 = @"str1";
    NSString *str2 = [str1 copy]; str1 = @"asdf"; NSLog(@"\nstr1 = %@ str1P = %p \n str2 = %@ str2P = %p", str1, str1, str2, str2); /*输出结果,修改str2 同理 str1 = asdf str1P = 0x10776b1a0 str2 = str1 str2P = 0x10776b180 */ 

那为什么NSString *str2 = [str1 copy];是不同的指针指向同一块内存空间,str1 从新赋值 后两个内存空间就不一样了呢?

因为str2 = str1的时候,两个字符串都是不可变的,指向的同一块内存空间中的 @"str1",是不可能变成@"abcd"的。所以这个时候,为了优化性能,系统没必要另外提供内存,只生成另外一个指针,指向同一块内存空间就行。
但是当你从新给 str1 或者str2赋值的时候,因为之前的内容不可变,还有互不影响的原则下,这个时候,系统会从新开辟一块内存空间。

问题2:copy 一个可变的数组,会出现什么结果?

我们直接上结果吧。。。

    NSMutableArray *mArr1 = [@[@"123", @"456", @"asd"] mutableCopy]; NSMutableArray *mArr2 = [mArr1 copy]; NSLog(@"\n mArr1 = %@ mArr1P = %p mArr1 class = %@ \n\n mArr2 = %@ mArr2P = %p mArr2 class = %@", mArr1, mArr1, [mArr1 class], mArr2, mArr2, [mArr2 class]); /*输出结果 mArr1 = ( 123, 456, asd ) mArr1P = 0x60400025db20 mArr1 class = __NSArrayM mArr2 = ( 123, 456, asd ) mArr2P = 0x60400025dd30 mArr2 class = __NSArrayI */ 

从结果看出,内存地址不一样,而且mArr2 是不可变的。copy为什么不是指针指向了?
首先,mArr2是通过copy 得来的,关键点在于copy,和mArr1 无关,所以他是不可变的。
另外,mArr1指向的内存空间是可变的,如果对mArr1进行修改,同一内存空间的内容就会变化。 遵循相会不影响的原则,加上mArr2是不可变的,mArr1 的内存空间已经不合适,所以此时的 copy从新开辟内存空间。

问题3:用 copy 修饰 NSMutableArray @property (nonatomic, copy) NSMutableArray *mArr;,对mArr 赋值会有什么结果?
    NSArray *arr = @[@"123", @"456", @"asd"]; self.mArr = [arr mutableCopy]; NSLog(@"\n arrP = %p \n self.mArrP = %p, self.mArr class = %@", arr, self.mArr, [self.mArr class]); /*输出结果 arrP = 0x60000044d1a0 self.mArrP = 0x60000044d1a0, self.mArr class = __NSArrayI */ 

可以看出内存地址不一样,但是_mArr 是不可变的数组。
因为 _mArr声明的时候是用 copy修饰,那么就限制了他为不可变的数组。 赋值的时候是用mutableCopy,可变数组的复制方法,所以会从新分配内存。

    NSArray *arr = @[@"123", @"456", @"asd"]; self.mArr = arr; NSLog(@"\n arrP = %p \n self.mArrP = %p, self.mArr class = %@", arr, self.mArr, [self.mArr class]); /*输出结果 arrP = 0x60400044ecd0 self.mArrP = 0x60400044ecd0, self.mArr class = __NSArrayI */ 

直接赋值,内存地址没变。

问题4:浅拷贝,不拷贝对象本身,仅仅是拷贝指向对象的指针。深拷贝,是直接拷贝整个对象内存到另一块内存中。 有什么看法?

浅拷贝,不拷贝对象本身,仅仅是拷贝指向对象的指针。不够严谨,在一些特殊请款下,还是会拷贝整个对象内存到另一块内存中。

总结:

  • 用copy修饰的 或者赋值的 变量肯定是不可变的。
  • 用copy赋值,要看源对象是否是可变的,来决定只拷贝指针,还是也拷贝对象到另一块内存空间
  • 对象之间mutableCopy赋值,肯定会拷贝整个对象内存到另一块内存中
  • 对象之间赋值之后,再改变,遵循互不影响的原则

转载于:https://www.cnblogs.com/jiuyi/p/11451226.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值