这个问题其实很简单, 但比较容易让人忽略.
解释这个问题前, 首先要明白, NSString属性为什么要用copy来修饰?
NSString属性之所有用copy来修饰, 是为了防止不同的指针变量指向同一个内存地址, 从而形成连带效应----就是改变一个变量的值, 另一个值也随之发生改变.比如:
@interface Demo()@property (strong, nonatomic)
NSString *S;
@end
@implementation
NSMutableString *MS = [[NSMutableString alloc] initWithString:@"ABC"];
_S = MS;
@end
这段代码里, 如果NSString属性不用copy而用strong修饰的话, 就会造成两个指针变量同时指向同一块存储空间的问题.具体原因如图:
代码中的"ABC"是存放在堆中的. 因为NSMutableString的initWithSring方法会将传入的参数从常量区中拷贝一份, 放入堆中.
这种情况下, 由于NSMutableString的特点就是只会对同一块内存进行操作, 所以不管是改变可变字符串"MS"的值, 还是改变实例对象"S"的值, 另一个对象的值也都会随之发生改变. 这样代码的管理就会非常混乱.
而如果用copy修饰的话, 在赋值的时候, 编译器会在setter方法中进行判断: 如果等号左边是一个可变字符串, 就让等号左边的指针变量指向一个copy出来的新地址, 这样就可以解决上面的问题.
如图:
这里写图片描述
那么, 为什么开发中NSString属性可以用strong呢?
因为实际开发中, 几乎用不到NSMutableString啊!!!
我们都是用一个NSString给另一个NSString赋值啊!!!
比如:
@interface Demo()@property (strong, nonatomic)
NSString *S;
@end
@implementation
NSString *MS = @"ABC";
_S = MS;
@end
这样的话, 在内存中就变成了:
这里写图片描述
这样看似两个指针变量又都指向了同一块内存, 但因为指向的是常量区, 而常量区的内容是不可改变的, 所以即使任何一方改变了指针指向中的内容, 编译器都会重新在常量区中开辟一块空间来保存新的内容, 然后改变该指针的指向, 让它重新指向新的内容.
比如
@implementation
NSString *MS = @"ABC";
_S = MS;
MS = @"EFG"
@end
内存示意图如下:
这里写图片描述
正是因为这样, 我们才可以在开发中将NSString属性的策略定义成strong.
那么用strong修饰NSString的意义何在呢?
前面提到过, 如果你用copy修饰了NSString, 那么编译器会在setter方法里进行判断参数和对象是可变还是不可变, 判断当然要消耗性能, 想想一个项目里有多少个字符串, 每一个字符串都消耗一点点性能, 那么多字符串加起来消耗的性能也是比较多的, 所以如果用strong来修饰, 可以在一定程度上减少一点无谓性能牺牲.(这也是我在开发中访问属性一直用"_"而不是"self."的原因)
当然, 如果用strong修饰了NSString属性的话, 必须要确保的就是将来给这个属性赋值时, 用的同样是NSString, 而不是NSMutableString
网友评论