基础知识

OC中用strong修饰的NSString什么情况下才会改变

2019-03-06  本文已影响3人  QYiZHong

前言

昨天跟人争论了一个问题:
两个使用strong修饰的NSString对象str1和str2,给str1赋值为@"123"然后再把str1赋给str2,然后此时再去改变str1。操作如下:

@property (nonatomic, strong) NSString *str1;
@property (nonatomic, strong) NSString *str2;

self.str1 = @"123";
self.str2 = self.str1;
NSLog(@"str1: %@, str2: %@", self.str1, self.str2);
NSLog(@"str1: %p, str2: %p", self.str1, self.str2);
self.str1 = @"321";
NSLog(@"str1: %@, str2: %@", self.str1, self.str2);
NSLog(@"str1: %p, str2: %p", self.str1, self.str2);

我之前的结论是只要他们都是strong修饰的,改了str1那么str2也会变。争论很激烈,然后我发现我错了...

结论是这样的

str1: 123, str2: 123
str1: 0x10471e060, str2: 0x10471e060
str1: 321, str2: 123
str1: 0x10471e0c0, str2: 0x10471e060

一开始他们确实是指向同一块内存地址,但是重新给str1赋值完,即使它是strong修饰的,它也变了一个新地址。

所以我现在有一个疑问,到底什么时候用strong修饰NSString才会改变?

验证

第一种,让str1为NSMutableString类型,通过赋值改变str1

@property (nonatomic, strong) NSMutableString *str1;
@property (nonatomic, strong) NSString *str2;

self.str1 = @"123".mutableCopy;
self.str2 = self.str1;
NSLog(@"str1: %@, str2: %@", self.str1, self.str2);
NSLog(@"str1: %p, str2: %p", self.str1, self.str2);
self.str1 = @"321".mutableCopy;
NSLog(@"str1: %@, str2: %@", self.str1, self.str2);
NSLog(@"str1: %p, str2: %p", self.str1, self.str2);

结论是直接通过赋值改变str1,str2仍然不会变。我对此的理解是赋值@"321".mutableCopy给str1,使得str1又指向了另一块内存地址,所以不会改变str2

str1: 123, str2: 123
str1: 0x10471e060, str2: 0x10471e060
str1: 321, str2: 123
str1: 0x10471e0c0, str2: 0x10471e060

第二种,让str1为NSMutableString类型,通过方法改变str1

@property (nonatomic, strong) NSMutableString *str1;
@property (nonatomic, strong) NSString *str2;

self.str1 = @"123".mutableCopy;
self.str2 = self.str1;
NSLog(@"str1: %@, str2: %@", self.str1, self.str2);
NSLog(@"str1: %p, str2: %p", self.str1, self.str2);
[self.str1 appendString:@"321"];
NSLog(@"str1: %@, str2: %@", self.str1, self.str2);
NSLog(@"str1: %p, str2: %p", self.str1, self.str2);

结论是str2随着str1改变了,我对此的理解是str1和str2都指向同一快内存地址,这个时候通过append去改变str1并不会给str1换一个内存地址,所以str2就随着str1改变了。

str1: 123, str2: 123
str1: 0x600000dd0ab0, str2: 0x600000dd0ab0
str1: 123321, str2: 123321
str1: 0x600000dd0ab0, str2: 0x600000dd0ab0

所以NSString的属性使用copy修饰的目的就在于预防这种情况。同理,其他的容器类对象也是一样的,比如说NSArray也要用copy去修饰。

最后

写在最后,我们应该去思考一下有没有一种别的办法让strong修饰的NSString类型不会随着NSMutableString对象的改变而改变。结论肯定是有的,那就是在把str1赋给str2时.copy一下做一次深拷贝。

self.str2 = self.str1.copy;

这样str2即使是strong修饰,也会因为与str1所指向的内存地址不同而不会随之改变。当然个人建议还是要遵守使用copy进行修饰,而且在手动把可变类型赋值给不可变类型是就顺手.copy一下。这样做的原因是你可能下意识会觉得一个NSString的属性会是copy修饰,但是你不能保证实际中的代码一定是这样。因为写代码难免会出现疏忽,可变类型赋值给不可变类型中copy一下只是增加了一点点损耗但是却能保证在这里赋值绝对不会出bug,这个价值是值得我们去这么做的。

上一篇下一篇

猜你喜欢

热点阅读