字符串修饰符strong和copy的区别

本文介绍了浅拷贝和深拷贝的概念,通过代码验证分析了Objective-C中strong和copy修饰符对NSString和NSMutableString的影响。在不可变对象间,二者效果相同;而在可变对象间,copy会产生深拷贝,防止原值被意外改变,而strong则是浅拷贝,可能导致数据安全性问题。因此,为防止数据意外变动,推荐在涉及可变与不可变对象转换时使用copy修饰。

一:概念
浅拷贝:指针拷贝,不会创建一个新的对象。浅拷贝简单点说就是对内存地址的复制,让目标对象指针和源对象指针指向同一片内存空间
深拷贝: 内容拷贝,会创建一个新的对象。深拷贝就是拷贝地址中的内容,让目标对象产生新的内存区域,且将源内存区域中的内容复制到目标内存区域中
深拷贝和浅拷贝的本质是内存地址是否相同

二:代码验证
定义两个属性

@property (nonatomic, strong) NSString  *stringStrong;
@property (nonatomic, copy)   NSString  *stringCopy;

情况1:
分别给这两个属性赋值NSString类型

    - (void)testStrongAndCopyStr{
    
    //情况1:给属性赋NSString类型的值
    NSString *strongStr = @"I am Strong";
    NSString *copyStr = @"I am Copy";
    self.stringStrong = strongStr;
    self.stringCopy = copyStr;
    
    //strongStr是一个指针变量(就是一个变量的地址),它指向strongStr对象的地址。&strongStr指的是strongStr这个指针变量本身所在的地址。
    ZWWLog(@"strongStr地址==%p,内容=%@, self.stringStrong地址==%p,内容=%@",strongStr,strongStr,self.stringStrong,self.stringStrong);
    ZWWLog(@"copyStr地址==%p,内容=%@, self.stringCopy地址==%p,内容=%@",copyStr,copyStr,self.stringCopy,copyStr);
   
    NSString *strong1Append =  [strongStr stringByAppendingString:@"+11111"];
    NSString *copy1Append = [copyStr stringByAppendingString:@"+22222"];
    ZWWLog(@"原字符串拼接后strong1Append地址==%p,strong1Append内容==%@,strongStr地址==%p,内容==%@, self.stringStrong地址==%p,内容==%@",strong1Append,strong1Append, strongStr,strongStr,self.stringStrong,self.stringStrong);
    ZWWLog(@"原字符串拼接后copy1Append地址=%p,copy1Append内容==%@,copy1地址==%p,内容==%@,self.stringCopy地址==%p,内容==%@",copy1Append,copy1Append, copyStr,copyStr,self.stringCopy,self.stringCopy);
    
    
    //情况2:给属性赋NSMutableString类型的值
    NSMutableString *mStrongStr = [NSMutableString stringWithFormat:@"I am MutableStrong"];
    NSMutableString *mCopyStr = [NSMutableString stringWithFormat:@"I am MutableCopy"];
    self.stringStrong = mStrongStr;
    self.stringCopy = mCopyStr;
    ZWWLog(@"mStrongStr地址==%p,内容==%@, self.stringStrong地址==%p,内容==%@", mStrongStr,mStrongStr,self.stringStrong,self.stringStrong);
    ZWWLog(@"mCopyStr地址==%p,内容==%@,self.stringCopy地址==%p,内容==%@", mCopyStr,mCopyStr,self.stringCopy,self.stringCopy);

    
    //两个MutableString进行操作(不返回值)
    [mStrongStr appendString:@"+11111"];
    [mCopyStr appendString:@"+22222"];
    ZWWLog(@"mStrongStr地址==%p,内容==%@, self.stringStrong地址==%p,内容==%@", mStrongStr,mStrongStr,self.stringStrong,self.stringStrong);
    ZWWLog(@"mCopyStr地址==%p,内容==%@,self.stringCopy地址==%p,内容==%@", mCopyStr,mCopyStr,self.stringCopy,self.stringCopy);
    
    
}

情况1打印结果:

strongStr地址==0x1099ed230,内容=I am Strong; self.stringStrong地址==0x1099ed230,内容=I am Strong
copyStr地址==0x1099ed250,内容=I am Copy; self.stringCopy地址==0x1099ed250,内容=I am Copy

分析:

  • strongStr和self.stringStrong指针变量地址相同,说明两个变量指向的是同一个内存地址,同一个对象,所以被赋值NSString类型时,strong修饰的变量是浅拷贝
  • copyStr和self.stringCopy指针变量地址相同,说明两个变量指向的是同一个内存地址,同一个对象,所以被赋值NSString类型时,copy修饰的变量也是浅拷贝

情况1中的被赋值NSString进行值改变,打印结果:

原字符串拼接后strong1Append地址==0x604000055ae0,strong1Append内容==I am Strong+11111,strongStr地址==0x1090cf230,内容==I am Strong, self.stringStrong地址==0x1090cf230,内容==I am Strong
原字符串拼接后copy1Append地址=0x604000055060,copy1Append内容==I am Copy+22222,copy1地址==0x1090cf250,内容==I am Copy,self.stringCopy地址==0x1090cf250,内容==I am Copy

分析:

  • NSString类型的变量stringByAppendingString方法返回是一个NSString类型的变量,这个变量地址不等于原来NSString的地址(内存地址),说明不可变字符串值不可改变,如果改变(比如拼接)就会变成一个全新的变量,所以NSString类型变量改变不会影响原来变量的值
  • 无论是strong修饰还是copy修饰,都不会因为被赋值NSString类型的值的改变而改变,因为NSString类型值改变压根不会影响原来值

情况2打印结果:

mStrongStr地址==0x604000047b00,内容==I am MutableStrong, self.stringStrong地址==0x604000047b00,内容==I am MutableStrong
mCopyStr地址==0x6040000481c0,内容==I am MutableCopy,self.stringCopy地址==0x60400004b0d0,内容==I am MutableCopy

分析:

  • mStrongStr和self.stringStrong地址相同,说明strong修饰的字符串和mStrongStr指向的是同一块内存,同一个对象,说明赋值NSMutableString时,strong修饰的字符串是浅拷贝
  • mCopyStr和self.stringCopy地址不同,说明copy修饰的字符串和mCopyStr指向的不是同一块内存,不是同一个对象,是对原来对象一份全新的拷贝,说明赋值NSMutableString时,copy修饰的字符串是深拷贝

情况2中的被赋值NSMutableString进行值改变,打印结果:

mStrongStr地址==0x604000047b00,内容==I am MutableStrong+11111, self.stringStrong地址==0x604000047b00,内容==I am MutableStrong+11111
mCopyStr地址==0x6040000481c0,内容==I am MutableCopy+22222,self.stringCopy地址==0x60400004b0d0,内容==I am MutableCopy

分析:

  • NSMutableString类型的变量appendString方法返回值是void,所以拼接完之后改变的还是原来字符串,因为strong修饰的字符串是浅拷贝,所以会跟随原来值改变而改变
  • 但是copy修饰的NSString字符串被赋值是NSMutableString时,是对原对象深拷贝,所以不会因为原值的改变而改变

面试时经常问到给NSString字符串设置为strong属性有什么风险,从上面就测试可以看出:
stong修饰的字符串无论被赋值NSString还是NSMutableString都是浅拷贝,被赋值NSString类型时没有问题和copy效果一样,但是当被赋值为NSMutableString类型时,它会因为被赋的值的改变而改变,这在很多情况下是存在风险的,因为大部分情况下我们是不希望自己的属性值在初始化后又莫名的改变的,当然如果原本需求就是希望无论什么时候都随被赋值改变而改变那就必须就用stong修饰了

还有一个经常和这个问题一块问到的有关深浅拷贝的问题:
问题:对NSMutableString类型属性用copy修饰会有什么问题,请参考我的这边博客
各种类型的深浅拷贝

总结:

在不可变对象之间进行转换,strong与copy修饰作用是一样的,但是如果在不可变与可变之间进行操作,那么就比较推荐copy, 这样可以不随着被赋值的改变而改变,这也就是为什么很多地方用copy,而不是strong修饰NSString,NSArray等存在可变不可变之分的类对象了,避免出现意外的数据操作.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值