背景
NSString 大家都不陌生了,但是用起来的时候,总是有点不清楚
今天主要和大家说下NSString的修饰符问题
首先,我们知道NSString 可以用copy修饰,那么,用strong修饰会怎么样, 如果可以,用assign修饰又会怎么样🤔️
基础的属性修饰符strong、copy、assign的区别就不讲了,直接上代码
实验
strong 修饰的NSString
先定义一个属性@property (nonatomic, strong) NSString *name;
然后写测试代码
NSMutableString *oName = [NSMutableString stringWithString:@"hello"];
myClass.name = oName;
oName = [NSMutableString stringWithString:@"world"];
NSLog(@"%@", ocm.name);
当我们执行上边的程序的时候,会发现输出的是hello
如果觉得有点奇怪,我们接着细研究一下
我们在oName = [NSMutableString stringWithString:@"world"];语句前打一个断点
这个时候在控制台查看可以发现两者指向同一个内存地址
p myClass.name
(__NSCFString *) $0 = 0x00006000023fc390 @"hello"
p oName
(__NSCFString *) $1 = 0x00006000023fc390 @"hello"
点击单步调试(一步一步调试更容易理解程序内部发生了什么 --来自老大对我的指导)让程序执行完oName = [NSMutableString stringWithString:@"world"];语句
这个时候我们再来看一下调试器输出
p myClass.name
(__NSCFString *) $2 = 0x00006000023fc390 @"hello"
p oName
(__NSCFString *) $3 = 0x0000600002335a70 @"world"
发现两者指向了不同的地址,确切的说是oName指向了新的地址。这就是我们所希望的结果,有人可能会有疑问,指向同一个内存的指针,一个变了,另一个内容居然不变?
但是如果仔细观察上边的输出,可以发现,当oName改变的时候,不是内存区域的值变了,而是,oName的地址变了。这个结论同样适用于属性是NSMutableString的情况和oName是NSString*类型的情况, 至于为什么变,这是后话
copy 修饰的NSString
同样的在oName = [NSMutableString stringWithString:@"world"];语句前打一个断点
p myClass.name
(NSTaggedPointerString *) $0 = 0xf2fe9bc4b2255f98 @"hello"
p oName
(__NSCFString *) $1 = 0x0000600001332610 @"hello"
注意,从赋值之后,两者就处于不同的内存地址中,所以后边的自然也不同了
问题
那么是什么导致了这个现象的发生,NSString的内容修改,字符串指向的地址就要修改吗
首先 导致这个现象的发生,是我在乱使用NSString🧎♂️, 不同于Swift,oc里的String变量有NSString 和NSMutableString
NSSring在官方文档中的解释是
A static, plain-text Unicode string object.
而且,官方也给了提示
An immutable string is a text string that is defined when it is created and subsequently cannot be changed.
所以,当我更改NSString*的值的时候, 例如myClass.name = oName;
本质上,是给原先的指针赋值了一个新的指针,使它指向了新的内存地址。这样才会有上面的错误
而更需要注意的是,当我们仅仅想更改一个字符串的值的时候, 注意 是仅仅想更改值,那么这个时候不应该使用NSString,
要使用NSMutableString
例如将上面的例子修改一下
NSMutableString *oName = [NSMutableString stringWithString:@"hello"];
NSMutableString *changeName=[NSMutableString stringWithString:@"change"];
oName = changeName;
[oNameappendString:@"world"];
当我们在[oNameappendString:@"world"];语句前打一个断点,查看值
p oName
(__NSCFString *) $0 = 0x000060000049b990 @"change"
p changeName
(__NSCFString *) $1 = 0x000060000049b990 @"change"
意料之中,继续单步执行并查看
p oName
(__NSCFString *) $2 = 0x000060000049b990 @"changeworld"
p changeName
(__NSCFString *) $3 = 0x000060000049b990 @"changeworld"
注意到了吗。这两者的地址并没有发生变化,所以,当一个的值发生变化,另一个也跟着变了
总结
所以,希望大家以后使用NSString的时候,分清楚自己要更改的是值,还是要赋值一个新的指针给原指针,如果只需要更改值,那么请使用NSMutableString, 换句话说,如果你可以直接在原地址更改NSString的值,那APPLE的那么多研发人员做NSMutableString是为了什么,一切代码都有它存在的原因。😄








网友评论