我们在声明一个NSString属性时,对于其内存相关特性,通常有两种选择(基于ARC环境):strong与copy。那这两者有什么区别呢?什么时候该用strong,什么时候该用copy呢?让我们先来看个例子。

示例

我们定义一个类,并为其声明两个字符串属性,如下所示:

1
2
3
4
@interface TestStringClass ()
@property (nonatomic, strong) NSString *strongString;
@property (nonatomic, copy) NSString *copyedString;
@end

上面的代码声明了两个字符串属性,其中一个内存特性是strong,一个是copy。下面我们来看看它们的区别。

首先,我们用一个不可变字符串来为这两个属性赋值,

1
2
3
4
5
6
7
8
- (void)test {
    NSString *string = [NSString stringWithFormat:@"abc"];
    self.strongString = string;
    self.copyedString = string;
    NSLog(@"origin string: %p, %p", string, &string);
    NSLog(@"strong string: %p, %p", _strongString, &_strongString);
    NSLog(@"copy string: %p, %p", _copyedString, &_copyedString);
}

其输出结果是:

1
2
3
origin string: 0x7fe441592e20, 0x7fff57519a48
strong string: 0x7fe441592e20, 0x7fe44159e1f8
copy string: 0x7fe441592e20, 0x7fe44159e200

我们要以看到,这种情况下,不管是strong还是copy属性的对象,其指向的地址都是同一个,即为string指向的地址。如果我们换作MRC环境,打印string的引用计数的话,会看到其引用计数值是3,即strong操作和copy操作都使原字符串对象的引用计数值加了1。

接下来,我们把string由不可变改为可变对象,看看会是什么结果。即将下面这一句

1
NSString *string = [NSString stringWithFormat:@"abc"];

改成:

1
NSMutableString *string = [NSMutableString stringWithFormat:@"abc"];

其输出结果是:

1
2
3
origin string: 0x7ff5f2e33c90, 0x7fff59937a48
strong string: 0x7ff5f2e33c90, 0x7ff5f2e2aec8
copy string: 0x7ff5f2e2aee0, 0x7ff5f2e2aed0

可以发现,此时copy属性字符串已不再指向string字符串对象,而是深拷贝了string字符串,并让_copyedString对象指向这个字符串。在MRC环境下,打印两者的引用计数,可以看到string对象的引用计数是2,而_copyedString对象的引用计数是1。

此时,我们如果去修改string字符串的话,可以看到:因为_strongString与string是指向同一对象,所以_strongString的值也会跟随着改变(需要注意的是,此时_strongString的类型实际上是NSMutableString,而不是NSString);而_copyedString是指向另一个对象的,所以并不会改变。

结论

由于NSMutableString是NSString的子类,所以一个NSString指针可以指向NSMutableString对象,让我们的strongString指针指向一个可变字符串是OK的。

而上面的例子可以看出,当源字符串是NSString时,由于字符串是不可变的,所以,不管是strong还是copy属性的对象,都是指向源对象,copy操作只是做了次浅拷贝。

当源字符串是NSMutableString时,strong属性只是增加了源字符串的引用计数,而copy属性则是对源字符串做了次深拷贝,产生一个新的对象,且copy属性对象指向这个新的对象。另外需要注意的是,这个copy属性对象的类型始终是NSString,而不是NSMutableString,因此其是不可变的。

这里还有一个性能问题,即在源字符串是NSMutableString,strong是单纯的增加对象的引用计数,而copy操作是执行了一次深拷贝,所以性能上会有所差异。而如果源字符串是NSString时,则没有这个问题。

所以,在声明NSString属性时,到底是选择strong还是copy,可以根据实际情况来定。不过,一般我们将对象声明为NSString时,都不希望它改变,所以大多数情况下,我们建议用copy,以免因可变字符串的修改导致的一些非预期问题。

本文【转载】自:http://www.cocoachina.com/ios/20150512/11805.html

补充:今天看到stackoverflow里面的解析,比较简单明了:

Think about this: NSMutableString is a subclass of NSString. When your property is declared as NSString, you don't expect it to change.

Consider, if you used retain and someone gave you an NSMutableString and then later on does change it, your class will be broken.

However, you may think that always copying is slow. So NSString's copy simply calls retainNSMutableString's copy makes an actual copy.

It is usually better to give spit out an NSString * because people won't have to copy it all the time.

NSString属性什么时候用copy,什么时候用strong?相关推荐

  1. (0087)iOS开发之NSString属性为什么要用copy来修饰?

    这个问题既是一个面试题,也是开发中经常遇到的问题,NSString 属性到底用copy 还是 strong ?其实如果明白的两者的区别也就不会疑惑了,其实都可以,只是如果你不明白两者的实质的区别,有可 ...

  2. IOS 关于NSString类型的属性为什么有时用copy,有时用strong呢?

    对于很多初学者,发现在修饰NSString类型的对象时,会有这样的疑惑?怎么有些人用strong修饰,而有些人用copy修饰呢? 这里有个例子,一.首先声明2个属性: @property (nonat ...

  3. NSString属性什么时候用copy,什么时候用strong?【转】

    转自:http://www.cocoachina.com/ios/20150512/11805.html. 我们在声明一个NSString属性时,对于其内存相关特性,通常有两种选择(基于ARC环境): ...

  4. OC指示符assign、atomic、nonatomic、copy、retain、strong、week的解释

    在使用@property定义property时可以在@property与类型之间用括号添加一些额外的指示符,常用的指示符有assign.atomic.nonatomic.copy.retain.str ...

  5. iOS属性之assign,copy,retain的区别以及weak和strong的区别

    为什么80%的码农都做不了架构师?>>>    @property (nonatomic, assign) NSString *title; 什么是assign,copy,retai ...

  6. @property 各个属性作用【使用时最需注意strong/weak类型】【补充部分内存知识】...

    一. 属性readwrite,readonly,assign,retain,copy,nonatomic 等各是什么作用,在那种情况下用? 1>  readwrite:同时生成get方法和set ...

  7. iOS中copy,retain,strong,assign,weak的区别以及使用

    使用assign: 对基础数据类型 (NSInteger)和C数据类型(int, float, double, char,等) 使用copy: 对NSString 使用retain: 对其他NSObj ...

  8. iOS strong和copy的区别

    级别: ★☆☆☆☆ 标签:「iOS」「NSString」「strong和copy」 作者: MrLiuQ 在iOS开发中,几乎每天都会遇到NSString属性的声明, 在ARC内存管理机制下, NSS ...

  9. python深拷贝和浅拷贝的使用场景_深拷贝、浅拷贝的理解与使用场景

    什么是深拷贝.浅拷贝? 通俗解释:深拷贝是内容拷贝,浅拷贝是地址拷贝 区别点: 深拷贝会创建一个新的内存空间,拷贝的值是一样的,但是内存地址不一样. 浅拷贝只是拷贝指向原来对象的地址,使原对象的引用计 ...

最新文章

  1. LeetCode Longest Repeating Character Replacement(滑动窗口)
  2. JVM垃圾回收3——参数详解(转载)
  3. ASP.NET Performance Monitoring, and When to Alert Administrators
  4. CentOS 卸载OpenJdk和Tomcat开机启动
  5. Spring七中传播行为详解
  6. WEB页面性能指标与建议
  7. 在线学编程python_我跟爸爸学编程:从Python到C++
  8. ROS的学习(九)理解ROS的参数
  9. 第二章 字符串处理与编码不再发愁
  10. 京东方10.1寸1280*800薄屏EV101WXM-N10-BOE工业屏
  11. 生成一个16位的随机数字
  12. 判断一个数是否是素数的 n 多种方法
  13. Mac下安装DBeaver
  14. 案例——淘宝轮播图和土豆网鼠标经过显示遮罩
  15. 计算机丢失dog.dll,dog.dll(解决找不到dog.dll文件问题)V1.0 正式版
  16. 【程序源代码】CRM客户关系管理系统
  17. 《零基础安装 Oracle 数据库》单机系列 ① 一键快速安装 Oracle 11GR2 数据库
  18. 【mysql】gh-ost使用说明
  19. Android之通过向WebService服务器发送XML数据获取相关服务
  20. 配置J2ME开发环境 Eclipse、eclipseME、WTK

热门文章

  1. win10 UWP 应用设置
  2. Unicode转义(\uXXXX)的编码和解码
  3. 【转】《iOS7 by Tutorials》系列:iOS7的设计精髓(上)
  4. C#按关闭按钮实现最小化,按ESC才关闭的实现【含系统消息大全】
  5. Jdk11,Jdk12的低延迟垃圾收集器ZGC
  6. 《Java: The Complete Reference》等书读书笔记
  7. C#编码标准--命名约定和风格
  8. 在ASP.NET中如何用C#.NET实现基于表单的验证
  9. 磁盘文件目录罗列和list控件的使用
  10. 远程过程调用RPC简介