美文网首页
NSMutableString 不要用 copy

NSMutableString 不要用 copy

作者: 凡几多 | 来源:发表于2020-10-08 23:06 被阅读0次

    疑问:

    我们都知道 copy 一般用来修饰 有对应可变类型的不可变对象上,比如 NSString,NSArrayNSDictionary。那么为什么不推荐用 copy 去修饰 NSMutableStringNSMutableArray 而是用 strong 呢?

    测试:

    平时没怎么关注过这个问题,那么我就来测试一下。

    一、先测试一下为什么 NSString 要用 copy

    首先定义两个字符串属性,一个 strong 一个 copy

    用 strong 修饰
    @property (nonatomic, strong) NSString *str_strong;
    
    用 copy 修饰
    @property (nonatomic, copy) NSString *str_copy;
    
    1、用可变字符串 NSMutableString 赋值:
    - (void)viewDidLoad {
        [super viewDidLoad];
        NSMutableString *mutString = [[NSMutableString alloc] initWithFormat:@"原可变字符串"];
        // 赋值
        self.str_strong = mutString;
        self.str_copy = mutString;    
        // 追加字符串
        [mutString appendString:@"+++追加字符串"];
        
        NSLog(@"\n mutString: %@, %p, %p \n str_strong: %@, %p, %p \n str_copy: %@, %p, %p \n" , mutString, mutString, &mutString, self.str_strong, _str_strong, &_str_strong, self.str_copy, _str_copy, &_str_copy);
    }
    

    打印结果如下:

     mutString: 原可变字符串+++追加字符串, 0x2828ab6f0, 0x16f027af8 
     str_strong: 原可变字符串+++追加字符串, 0x2828ab6f0, 0x127f0cab0 
     str_copy: 原可变字符串, 0x2828ab8a0, 0x127f0cab8
    

    可以看出 str_strongmutString 指向对象内存是一样的,因为 strong浅拷贝(指针拷贝),他们指向的都是同一个对象,地址没有变化,值当然也就一样了。
    str_copy 指向对象的内存地址和他们不一样,因为 str_copy 对象使用的 copy 深拷贝,是一个新的对象,开辟了新的内存地址,不用以前的地址。

    2、用不可变字符串 NSString 赋值:
    - (void)viewDidLoad {
        [super viewDidLoad];
        NSString *str = [[NSString alloc] initWithFormat:@"不可变字符串"];
        //进行赋值
        self.str_strong = str;
        self.str_copy = str;
        NSLog(@"\n str: %@, %p, %p \n str_strong: %@, %p, %p \n str_copy: %@, %p, %p \n" , str, str, &str, self.str_strong, _str_strong, &_str_strong, self.str_copy, _str_copy, &_str_copy);
    }
    

    打印结果如下:

     str: 不可变字符串, 0x283d55860, 0x16fbcbaf8 
     str_strong: 不可变字符串, 0x283d55860, 0x100a15bf0 
     str_copy: 不可变字符串, 0x283d55860, 0x100a15bf8
    

    通过打印结果可以看出,str、str_strongstr_copy 这三者指向对象内存一样,不管是 strong 还是 copy 在这里都进行了 浅拷贝,没有重新开辟新的空间,因为这回的strNSString,是不可变的。

    所以一般我们是不希望我们创建的 NSString 字符串跟着之后的赋值 mutString 变化而变化的,所以都用 copy 。当然如果你希望字串的值跟着 mutString 变化,也可以使用 strong
    但是,如果你创建的是 NSMutableString,那么不要用 copy

    二、NSMutableString 不要用 copy

    我们使用 NSMutableString 肯定是想用字符串的可变这个属性,但如果你用 copy 去修饰,那么生成的将会是不可变的,当你去调用可变方法时,程序将会崩溃!
    测试:

    用 copy 修饰 NSMutableString
    @property (nonatomic, copy) NSMutableString *mutstr_copy;
    

    同理,也不要对 NSMutableArrayNSMutableDictionary 使用 copy 修饰,不然也有可能出现崩溃。

    三、总结

    • 1、当原字符串是 NSString ,即不可变字符串时,不管是 strong 还是 copy 属性的对象,都指向原对象,copy操作也只是做了浅拷贝。

    • 2、当原字符串是 NSMutableString 时,即可变字符串时,strong 属性只是增加了原字符串的引用计数,而 copy 属性则是对原字符串做了次深拷贝,产生一个新的对象,且 copy 属性对象指向这个新的对象,且这个 copy 属性对象的类型始终是 NSString,而不是NSMutableString,因此其是不可变的,这时候调用可变操作,将会造成崩溃!

    • 3、 因为 NSMutableStringNSString 的子类,父类指针可以指向子类对象,使用 copy 的目的是为了让本对象的属性不受外界影响,这样无论给我传入是一个可变对象还是不可变对象,我本身持有的就是一个不可变的副本,这样更安全。

    所以,在声明 NSString 属性时,一般我们都不希望它改变,所以大多数情况下,我们建议用 copy,以免因可变字符串的修改导致的一些非预期问题。而在声明 NSMutableString 则需要使用 strong

    举一反三:

    NSMutableArraycopy 修饰有时就会崩溃,因为对这个数组进行了增删改操作,而 copy 后的数组变成了不可变数组 NSArray ,没有响应的增删改方法,所以就崩溃了。

    • 当修饰可变类型的属性时,如 NSMutableArray、NSMutableDictionary、NSMutableString,用 strong
      当修饰不可变类型的属性时,如 NSArray、NSDictionary、NSString,用 copy

    相关文章

      网友评论

          本文标题:NSMutableString 不要用 copy

          本文链接:https://www.haomeiwen.com/subject/nbwhpktx.html