NSString用copy, NSMutableString用strong.

上代码:

//定义两个属性:
/** strong修饰的字符串 **/
@property (nonatomic, strong) NSString *sString;
/** copy修饰的字符串 **/
@property (nonatomic, copy) NSString *cString;

- (void)test {
    NSMutableString *mString = [[NSMutableString alloc] initWithFormat:@"我是可变的字符串"];
    
    //进行赋值
    self.sString = mString;
    self.cString = mString;
    
    NSLog(@"\n mString: %@, %p, %p \n sString: %@, %p, %p \n cString: %@, %p, %p", mString, mString, &mString, self.sString, _sString, &_sString, self.cString, _cString, &_cString);
    
    //打印结果(指针所指向对象的内存地址,指针内存地址)
    /**
     mString: 我是可变的字符串, 0x60000386d020, 0x7ffeebc11a70
     sString: 我是可变的字符串, 0x60000386d020, 0x7f9f2e913830
     cString: 我是可变的字符串, 0x60000386d590, 0x7f9f2e913838
     */
    
    //追加字符串
    [mString appendString:@"我是追加的字符串"];
    
    NSLog(@"\n mString: %@, %p, %p \n sString: %@, %p, %p \n cString: %@, %p, %p", mString, mString, &mString, self.sString, _sString, &_sString, self.cString, _cString, &_cString);
    
    //打印结果(指针所指向对象的内存地址,指针内存地址)
    /**
     mString: 我是可变的字符串我是追加的字符串, 0x60000386d020, 0x7ffeebc11a70
     sString: 我是可变的字符串我是追加的字符串, 0x60000386d020, 0x7f9f2e913830
     cString: 我是可变的字符串, 0x60000386d590, 0x7f9f2e913838
     */
}

分析:

  • strong修饰的sString指向对象的内存地址和mString指向对象内存地址是一样的, 就是说sString和mString指向的是同一个对象@“我是可变的字符串”,这个对象的地址没有变化,所以它们的值是一样的.
  • 而copy修饰的cString指向对象的内存地址却和它们不同,因为当把mString赋值给copy的cString时,cString对象是深拷贝而来,一个新的对象,这个对象有新的地址不再是原来的地址了.也就是开辟了新的内存地址.
  • 从输出结果看,当mString追加新的内容后,cString的内容没有发生改变. sString的内容发生了改变.因为strong是浅拷贝(指针拷贝),而copy是深拷贝,开辟了新的内存地址,这样更安全,特别是NSArray和NSDictionary,如果值被莫名其妙的改变了,那就只能gg了.

1.如果用不可变得字符串进行赋值,会发生什么呢?
上代码:

- (void)test {
    NSString *string = [[NSString alloc] initWithFormat:@"我是不可变的字符串"];
    
    //进行赋值
    self.sString = string;
    self.cString = string;
    
    NSLog(@"\n string: %p, %p \n sString: %p, %p \n cString: %p, %p", string, &string, _sString, &_sString, _cString, &_cString);
    
    //打印结果(指针所指向对象的内存地址,指针内存地址)
    /**
     string: 0x6000027c1e90, 0x7ffee934ea58
     sString: 0x6000027c1e90, 0x7f89c6d0cdc0
     cString: 0x6000027c1e90, 0x7f89c6d0cdc8
     */
}

分析:

  • 可以看到,无论是strong还是copy,在这里都是进行了浅拷贝,不会重新开辟新的空间.因为被赋值的对象本身string是不可变的,有一定的安全性,那么那些后来进行copy,strong的也同样不会影响安全性,而且内存管理也一样.

2.自定义类如何让它具有copy功能?
遵守NScoping协议,实现copywithzone方法即可.
代码:

 -  (id)copyWithZone:(NSZone *)zone {
         Student *student = [[Student allocWithZone:zone] initWithName: self.name age:self.age];
         return student;
}

分析:

  • 浅拷贝:指针赋值,使两个指针指向相同的一块内存空间,操作不安全。
  • Foundation类已经遵守了和 协议,即实现了copy和mutableCopy方法,因此Foundation对象可以使用这些方法创建对象的副本或可变副本

3.用copy和strong关键字的原因分析.

  1. 一般情况下,我们不希望我们创建的字符串跟着mStr变化而变化,故用copy.如果希望字串的值跟着mStr变化,可以使用strong,retain来修饰.
  2. 通常情况下,因为父类指针可以指向子类对象,使用copy的目的是为了让本对象的属性不受外界影响,使用copy来修饰无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本,这样更安全.
  3. <1>.总结: 对于用NSMutableString的字符串来赋值,strong声明的属性不管是可变的还是不可变得,都会浅拷贝,只拷贝指针地址,会随着mString的改边而改变.而copy声明的属性不管是可变的还是不可变得,都会深拷贝,堆区开辟新的空间,不会随着mString的改变而改变.
    <2>.对于用NSString的字符串来赋值,不管是strong声明的属性还是copy声明的属性,也不管他们各自是可变的还是不可变得,都会浅拷贝,此时copy也是浅拷贝,不会在堆区开辟新空间.
    <3>说白了就是一个安全的问题,声明一个NSString *str变量,然后把一个NSMutableString *mStr变量的赋值给它了如果要求str跟着mStr变化那么就用strong;如果str不能跟着mStr一起变化那就用copy而对于要把NSString类型的字符串赋值给str,那两都没啥区别。
  4. –>copy此特质所表达的所属关系与strong类似。
    –>然而设置方法并不保留新值,而是将其“拷贝” (copy)。
    –>当属性类型为NSString时,经常用此特质来保护其封装性,因为传递给设置方法的新值有可能指向一个NSMutableString类的实例。
    –>这个类是NSString的子类,表示一种可修改其值的字符串,此时若是不拷贝字符串,那么设置完属性之后,字符串的值就可能会在对象不知情的情况下遭人更改。
    –>所以,这时就要拷贝一份“不可变” (immutable)的字符串,确保对象中的字符串值不会无意间变动。
    –>只要实现属性所用的对象是“可变的” (mutable),就应该在设置新属性值时拷贝一份。
  5. 浅拷贝 — 只拷贝对象地址,不会拷贝内容,不会开辟新的空间.
    深拷贝 — 拷贝内容,堆区开辟新的空间,拷贝出的内容是可变的.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值