NSString到底是用copy还是strong?

我想通过一个最简单的例子来说明它们的区别:

首先我们来看看使用strong会出现什么样的情况:

.h

@property (nonatomic, strong) NSString *name;

.m

NSMutableString *mStr = [NSMutableString stringWithString:@"张三"];

self.name = mStr;

NSLog(@"使用strong第一次得到的名字:%@", self.name);

[mStr appendString:@"丰"];

NSLog(@"使用strong第二次得到的名字:%@", self.name);

打印结果:

2017-04-07 16:20:10.138793 copyTest[2421:682898] 使用strong第一次得到的名字:张三

2017-04-07 16:20:10.138884 copyTest[2421:682898] 使用strong第二次得到的名字:张三丰

结论:

通过上面的例子我们可以看出,我们在没有直接修改 self.name 的情况下 self.name 却被修改了,就好像一个人的名字怎么能没有经过自己同意就被修改呢?我们的初衷只是想修改mStr,但是 self.name 却被意外的修改了,而这就是我们使用strong所不想看到的,它会破坏程序的封装性。(使用strong后 self.name 和 mStr 指向的是同一片内存,所以修改其中一个值后两个值就都变了)

那么使用copy又会得到什么结果呢?下面是使用copy的例子:

.h

@property (nonatomic, copy) NSString *name;

.m

NSMutableString *mStr = [NSMutableString stringWithString:@"张三"];

self.name = mStr;

NSLog(@"使用copy第一次得到的名字:%@", self.name);

[mStr appendString:@"丰"];

NSLog(@"使用copy第二次得到的名字:%@", self.name);

打印结果:

2017-04-07 16:35:04.012589 copyTest[2428:685221] 使用copy第一次得到的名字:张三

2017-04-07 16:35:04.012676 copyTest[2428:685221] 使用copy第二次得到的名字:张三

结论:

这个例子中我们使用了copy修饰,mStr通过copy得到了一个新的对象赋值给 self.name 这样我们再修改mStr就跟 self.name 没关系了,只有直接对 self.name 进行赋值才能改变它的值,这样就保证了程序的封装性。

为什么使用copy而不是strong以上只是一个例子,还有很多情况可以自己去试试,并且可以把属性类型改成NSMutableString进行不同情况的研究,也可以更加深入理解深拷贝和浅拷贝的含义。

总结:

因为copy安全!

copy修饰的NSString,在初始化时,如果来源是NSMutableString的话,会对来源进行一次深拷贝,将来源的内存地址复制一份,这样,两个对象就一点关系就没有了,无论你怎么操作来源,都不会对自己的NSString有任何影响。

  • 那么问题来了,既然copy安全,那为什么不都用copy?
    这里我们需要了解一点,copy修饰的NSString在进行set操作时,底层是这样实现的:
    我们还是举上面那个例子,进行str = sourceStr操作时,内部会执行一个操作:
    str = [sourceStr copy];
    那么这个copy里面做了什么呢?
    if ([str isMemberOfClass:[str class]])
    没错,就是进行一次判断,判断来源是可变的还是不可变的,如果是不可变,那么好,接下来的操作就跟strong修饰的没有区别,进行浅拷贝;如果是可变的,那么会进行一次深拷贝
所以,copy操作内部会进行判断,你别小看了这个if操作所消耗的内存,一次不重要,十次可能也可以忽略不计,但当你的项目十分庞大时,有成百上千个个NSString对象,多多少少会对你的app的性能造成一定的影响.


猜你喜欢

转载自blog.csdn.net/shubinniu/article/details/79545684
今日推荐