NSString用copy, NSMutableString用strong.
程序员文章站
2024-01-15 08:41:52
...
上代码:
//定义两个属性:
/** 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关键字的原因分析.
- 一般情况下,我们不希望我们创建的字符串跟着mStr变化而变化,故用copy.如果希望字串的值跟着mStr变化,可以使用strong,retain来修饰.
- 通常情况下,因为父类指针可以指向子类对象,使用copy的目的是为了让本对象的属性不受外界影响,使用copy来修饰无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本,这样更安全.
- <1>.总结: 对于用NSMutableString的字符串来赋值,strong声明的属性不管是可变的还是不可变得,都会浅拷贝,只拷贝指针地址,会随着mString的改边而改变.而copy声明的属性不管是可变的还是不可变得,都会深拷贝,堆区开辟新的空间,不会随着mString的改变而改变.
<2>.对于用NSString的字符串来赋值,不管是strong声明的属性还是copy声明的属性,也不管他们各自是可变的还是不可变得,都会浅拷贝,此时copy也是浅拷贝,不会在堆区开辟新空间.
<3>说白了就是一个安全的问题,声明一个NSString *str变量,然后把一个NSMutableString *mStr变量的赋值给它了如果要求str跟着mStr变化那么就用strong;如果str不能跟着mStr一起变化那就用copy而对于要把NSString类型的字符串赋值给str,那两都没啥区别。 - –>copy此特质所表达的所属关系与strong类似。
–>然而设置方法并不保留新值,而是将其“拷贝” (copy)。
–>当属性类型为NSString时,经常用此特质来保护其封装性,因为传递给设置方法的新值有可能指向一个NSMutableString类的实例。
–>这个类是NSString的子类,表示一种可修改其值的字符串,此时若是不拷贝字符串,那么设置完属性之后,字符串的值就可能会在对象不知情的情况下遭人更改。
–>所以,这时就要拷贝一份“不可变” (immutable)的字符串,确保对象中的字符串值不会无意间变动。
–>只要实现属性所用的对象是“可变的” (mutable),就应该在设置新属性值时拷贝一份。 - 浅拷贝 — 只拷贝对象地址,不会拷贝内容,不会开辟新的空间.
深拷贝 — 拷贝内容,堆区开辟新的空间,拷贝出的内容是可变的.
推荐阅读
-
NSString属性何时用strong何时用copy?
-
iOS开发 -- 属性用copy、strong修饰的区别
-
NSString用copy, NSMutableString用strong.
-
NSString属性何时用strong何时用copy?
-
iOS 开发 NSString(NSDictory,NSArray)为什么用copy修饰,而不是用strong修饰
-
NSString什么时候用copy,什么时候用strong
-
iOS @property中的NSString, NSArray, NSDictionary属性为什么大多时候用copy而不用strong的原因
-
自己用Word制作简历看到付费的模板可以Copy其创意
-
php copy()函数有什么用
-
iOS 开发 NSString(NSDictory,NSArray)为什么用copy修饰,而不是用strong修饰