iOS NSString,NSArray,NSDictionary的Copy属性使用

在平时使用NSArray,NSDictionary以及NSString的过程中,经常会默认写了strong 属性,或者按照规范使用Copy,在Apple的规范中,是提倡我们使用copy的属性。

基本原理

  • 简单来说,copy属性就像字面意思一样,在赋值的时候会系统自动copy一份内存出来,修改新的变量,并不会导致原先的变量出现改变

即:

@property (nonatomic,strong) NSMutableString *strCopyA;
@property (nonatomic,copy) NSMutableString *strCopyB;
{
    self.strCopyA = [NSMutableString stringWithFormat:@"strCopyA"];
    self.strCopyB = self.strCopyA;
}

对比内存地址:

strB    - 0x7f97da5a0cd0
strA    - 0x7f97da5a0e30

从内存地址,我们就可以看出,两者

但是同学们需要注意到这里用到的mutable 可变容器,而不是我们平时用的NSString

  • NSString 属性下使用copy 和 strong 其实是一个作用的,copy并不会起作用,因为NSString是不可变的,所以copy没用

copy和strong 实际在的差异就在于setter的生成的方式不一样,可以简单的看下面(ARC模式下...),但是这个是针对mutable容器的

//copy
- (instancetype)setStr:(NSMutableString *)str
{
  _str = [str copy];
  return _str;
}
//strong
- (instancetype)setStr:(NSMutableString *)str
{
  _str = str;
  return str;
}
  • 从而可以看出两者的差别:开辟新内存,和新建一个计数引用
    测试:

      NSMutableString *mutStr = [NSMutableString stringWithFormat:@"原始"];
    
      self.strCopy = mutStr;
      self.strStrong = mutStr;
      NSLog(@"-----------修改----------------------");
      [mutStr appendString:@" + 添加了"];

    结果:可以看到只有Copy的那一栏的内存地址改动了,所以修改原来的变量,并不会导致新Copy的内存被修改,然而在Strong下,因为是同一块内存,仅仅是retain count +1 了而已,所以还是持有同一块内存,修改会同时显示在两个对象上

    mutStr      = 原始     - 0x7ff27ac531f0
    strCopy     = 原始     - 0x7ff27ac48b40
    strStrong   = 原始     - 0x7ff27ac531f0
    -----------修改----------------------
    mutStr      = 原始 + 添加了     - 0x7ff27ac531f0
    strCopy     = 原始             - 0x7ff27ac48b40
    strStrong   = 原始 + 添加了     - 0x7ff27ac531f0
  • NSString是NSMutableString的父类,父类可以接受子类的类型,因此当NSString 设定为copy的时候,它会在接受NSmutableString 的时候起到效果,从而才赋值的是另外copy了一份,不至于让 NSString 在调用mutable的方法的时候 产生错误。
    测试:

     self.strA = [NSMutableString string];
     self.strB = [NSMutableString stringWithString:@"B"];
    
     [self.strA setString:self.strB]; // 崩溃位置
    
     self.strB = self.strA;

    原因: self.strB真实类型是NSString不可变,因为strB使用copy属性,在赋值B的时候,@"B"为NSString类型,因此导致真实类型被修改,所以在NSString调用NSMutableString的方法会异常。

copy 和 mutableCopy方法

  • 实际上,@property (nonatomic,copy) 只有copy属性,而没有mutableCopy的修饰符,因此,[str copy]执行完的都是immutable不可变类型,所以我们看copy是否起作用,主要是看Setter方法中传入的参数的真实类型来决定是否copy开辟可以内存空间,因为[immutable copy]是浅拷贝,[mutable copy]是深拷贝

  • 直观点由setter方法 内部查看...

//@property (nonatomic,copy) NSMutableString *disStr;
- (void)setDisStr:(id)sourceStr
{
    _disStr = [sourceStr copy];//取决于sourceStr的类型,如果是immutable则为浅拷贝,如果是mutable则是深拷贝
    //返回的类型为immutable,不能调用mutable的方法了(runtime)
}
  • 如果需要用mutableCopy 的方法 就唯有自己去重写setter 方法了

初步结论

  • NSString 使用 copy, 而NSMutableString则推荐使用strong,避免埋下地雷炸死自己。

浅拷贝(shallow copy)和深拷贝(deep copy)


浅拷贝


深拷贝


浅拷贝,只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针

什么时候使用?

  • 无论深浅,都是得根据需求而去决定怎么使用。当深拷贝发生时,通常表明存在着一个“聚合关系”,而浅拷贝发生时,通常表明存在着一个“相识关系”。
  • 是深拷贝还是浅拷贝,并不是取决于时间效率、空间效率或是语言等等,而是取决于哪一个是逻辑上正确的。
  • 总的来说,一句话就是什么场景决定在怎么使用,然而请看下面的场景使用:

场景使用

NSArray 和 NSString实际是都是一样的效果,如果是在使用NSMutableArray 的时候使用copy 的值,那在例如tableview 下的dataSource,在赋值的时候,会另外mutableCopy一份新的,前后不干扰。

  • 我们假设一个意图,一般情境下,我们使用NSArray类型就是为了得到一个不可变的类型,也不希望有人再去改动,否则我们是会使用NSMutableArray去修改需要改动的array;

  • 我们解释这个意图:我想得到一个不可变的copyNSArray,也不希望其他人修改:

    @property (nonatomic,copy) NSArray *copyNSArray;
    @property (nonatomic,strong) NSMutableArray *strongMutableNSArry;
    {
       copyNSArray = strongMutableNSArry;
    }

    我们根据这个行为,判断你是需要一个新的值,从而让后续的操作不对原先的值进行更新,因为你使用的NSArray不可变类型,这时候,因为copyNSArray copy 了 strongMutableNSArry,因此两者已经不相关。
    -- 目标达成

  • 意图:我想得到一个可改变的array,希望可以在其他地方修改

    @property (nonatomic,strong) NSMutableArray *strongMutableNSArryA;
    @property (nonatomic,strong) NSMutableArray *strongMutableNSArryB;
    {
       strongMutableNSArryA = strongMutableNSArryB;
    }

    使用strong的情况下,strongMutableNSArryA = strongMutableNSArryB,两者指向同一个内存块,因此我们实际上是在使用同一个可变string,这个情况下使用mutable的方法并不出现问题。
    -- 目标达成

  • 意图:同第一个,我想得到一个不可变的值
    @property (nonatomic,strong) NSArray * strongNSArray;
    @property (nonatomic,strong) NSMutableArray *strongMutableNSArry;
    {
       strongNSArray =  strongMutableNSArry;
    }
    使用了strong ,两者使用同一个内存,一旦失手修改了strongMutableNSArry的值,你的不变值strongNSArray也会被修改
    -- 目标不达成

结论

  • 因此,结论是,NSString,NSArray,NSDictonary,使用copy属性,而其NSMubtableString,NSMutableArray, NSMutableDictonary属性则使用strong属性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值