美文网首页
16为什么NSString要用Copy来修饰?

16为什么NSString要用Copy来修饰?

作者: i爱吃土豆的猫 | 来源:发表于2017-10-14 23:47 被阅读229次
    // 深复制
    Person *xiaoMing = [[Person alloc] init];
    NSMutableString * name = [[NSMutableStringalloc] initWithString:@"xiaoming"];
    //name.string = @"xiaoming";
    xiaoMing.name = name;
    NSLog(@"%@", xiaoMing.name);
    [name appendString:@"hah"];
    
    //此时名字这个属性被修改了
    NSLog(@"%@", xiaoMing.name);
    

    如果用Copy来修饰name这个属性不会改变,
    如果使用Strong,当name这个字符串改变的时候,name这个属性也会随着改变。

    补充:这其实也是看需求,看被赋值的字符串是否需要随着赋值字符串的变化而变化,而大多数情况下我们不希望被赋值的字符串如某个对象的某个字符串类型的属性会随着赋值字符串的变化而变化。 反之,如果我们希望被赋值的字符串随着赋值字符串的变化而变化,那么我们也可以使用strong来修饰字符串(赋值字符串和被赋值字符串说的好像挺绕口啊)。注:赋值字符串既然可变,那它就必然是可变字符串。

    至于其底层原理区别则是两种修饰方式让指针指向的内存地址不同。使用copy修饰被赋值字符串,被修饰字符串会对赋值字符串(可变字符串)进行一次深拷贝,那么被赋值字符串和赋值字符串指向的是完全不同的两块内存地址,反之两者指向的同一块内存地址。

    当我们确定赋值字符串是不可变字符串的时候我们是可以使用strong来修饰字符串。

    联想:由copy修饰字符串想到的用strong修饰数组,原理是一样的,当我们用strong来修饰不可变数组的时候,如果赋值数组是可变数组,那么被赋值数组同样会随着可变数组的变化而变化。

    -  (void)viewDidLoad {
        [super viewDidLoad];
    
        NSMutableString *mStr = [NSMutableString stringWithFormat:@"mutablestring----"];
        self.name = mStr;
        [mStr appendString:@"addstriing"];//name的修饰符为copy时,name的结果为mutablestring----
        NSLog(@"%@",mStr);//name的修饰符为strong时,name的结果为mutablestring----addstriing
        NSLog(@"%@",self.name);
    }
    

    如下所示,当修饰符为copy时,因为NSMutableString是NSString类型的子类,所以可以用指针self.name指向mStr,但是我们知道copy的含义是指当重新赋值时深拷贝新对象再赋值给self.name,

    所以此时self.name的指针和mStr的指针指向的对象就不同了,所以当给mStr对象发送方法appendString的时候,修改的只是mStr(此时的值变为mutablestring----addstring),而self.name依然不变(mutablestring----);相反当修饰符为strong时,因为strong的意思是指针指向原对象,并且引用计数+1,所以self.name和mStr指向同一个对象,当修改mStr时self.name也会一起变化。所以为了避免NSString类型的值被修改,一般建议用copy修饰符修饰。

    第三篇

    那么,什么时候用copy,什么时候用strong呢?
    首先,为什么要用copy?

    因为copy安全!
    copy修饰的NSString,在初始化时,如果来源是NSMutableString的话,会对来源进行一次深拷贝,将来源的内存地址复制一份,这样,两个对象就一点关系就没有了,无论你怎么操作来源,都不会对自己的NSString有任何影响
    比如:
    你有一个@property(nonatomic,copy) NSString *str;
    然后有一个NSMutableString *sourceStr;
    当你进行str = sourceStr操作之后,紧接着你又改变了sourceStr的内容sourceStr = @"change";那么str的内容并不会改变. 如果你的str不是copy修饰的,而是strong修饰的,那么str的值也会变成@"change";因为strong是浅拷贝的,并不会对来源的内存地址进行拷贝
    那么问题来了,既然copy安全,那为什么不都用copy?
    这里我们需要了解一点,copy修饰的NSString在进行set操作时,底层是这样实现的:
    我们还是举上面那个例子,进行str = sourceStr操作时,内部会执行一个操作:
    str = [sourceStr copy];
    那么这个copy里面做了什么呢?
    if ([str isMemberOfClass:[str class]])
    没错,就是进行一次判断,判断来源是可变的还是不可变的,如果是不可变,那么好,接下来的操作就跟strong修饰的没有区别,进行浅拷贝;如果是可变的,那么会进行一次深拷贝
    所以,copy操作内部会进行判断,你别小看了这个if操作所消耗的内存,一次不重要,十次可能也可以忽略不计,但当你的项目十分庞大时,有成百上千个个NSString对象,多多少少会对你的app的性能造成一定的影响.

    那么回到最初的问题,什么时候用copy,什么时候用strong

    你只需要记住一点,当你给你的的NSString对象赋值时,如果来源是NSMutableString,那么这种情况就必须要用copy;如果你确定来源是不可变类型的,比如@"http://www.jianshu.com/users/691d9ed740cf/latest_articles"这种固定的字符串,那么用strong比较好

    相关文章

      网友评论

          本文标题:16为什么NSString要用Copy来修饰?

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