声明字符串变量我们可以使用:
@property (nonatomic,copy) NSString *stringStr;
也可以:
@property (nonatomic,strong) NSString *stringStr;
二者的声明使用好像在开发中也并无遇到过什么问题,那为什么我们建议使用copy,而不建议使用strong 呢,看下面一段示例代码你就全明白了:
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic,strong) NSString *stringStr;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.stringStr = [[NSMutableString alloc] initWithString:@"hello"];
NSLog(@"self.stringStr:%@",self.stringStr);
NSMutableString *stringStr2 = (NSMutableString *)self.stringStr;
NSLog(@"stringStr2:%@",stringStr2);
[stringStr2 appendString:@"你好世界"];
NSLog(@"stringStr2:%@",stringStr2);
NSLog(@"self.stringStr:%@",self.stringStr);
}
@end
输出结果是:
2017-11-29 13:37:48.601621+0800 test[35274:2369583] self.stringStr:hello
2017-11-29 13:37:48.601726+0800 test[35274:2369583] stringStr2:hello
2017-11-29 13:37:48.601822+0800 test[35274:2369583] stringStr2:hello 你好世界
2017-11-29 13:37:48.601899+0800 test[35274:2369583] self.stringStr:hello 你好世界
说明:我们用一个strong来修饰一个NSString *stringStr,当我们把它赋值给一个NSMutableString *stringStr2(NSMutableString 是NSString的子类,所以是直接可以赋值的)当我们给[stringStr2 appendString:@"你好世界"];追加字符串时,看输出结果,我们发现stringStr的值也变了。
举个形象的例子:试想你给你儿子去上户口,你的名子已经在户口上,你是不希望它再去更改的,结果给你儿子上完户口,你的名字也变了,fuck,多么可怕,试想,你给儿子上完护口后,没有去看你自己的信息,突然有一天,银行告诉你没你户名和银行卡不匹配,这又很尴尬了,本来是你上完户口,你是觉得你的名字是几乎是永远不会改变的,但是你儿子上了户口后影响了你的名字,而此时又没告知你,导致你在办理其他业务时出现一些异常。
这就好像我们用一个strong来修饰一个NSString *stringStr,如果stringStr的值直接赋给NSMutableString *stringStr2,随后stringStr2改变了 [stringStr2 appendString:@"你好世界"];,然后stringStr不知道,输出结果是stringStr也改变了。(内在主要是二者都是指向的同一个内存地址,一开始值是不可变的,后来变成了可变的,所以就会发生意想不到的事情)
二 我们换成copy来修饰看看
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic,copy) NSString *stringStr;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.stringStr = [[NSMutableString alloc] initWithString:@"hello"];
NSLog(@"self.stringStr:%@",self.stringStr);
NSMutableString *stringStr2 = (NSMutableString *)self.stringStr;
NSLog(@"stringStr2:%@",stringStr2);
[stringStr2 appendString:@"你好世界"];
NSLog(@"stringStr2:%@",stringStr2);
NSLog(@"self.stringStr:%@",self.stringStr);
}
@end
输出结果:
2017-11-29 14:16:01.086722+0800 test[35581:2441346] self.stringStr:hello
2017-11-29 14:16:01.086831+0800 test[35581:2441346] stringStr2:hello
2017-11-29 14:16:01.086966+0800 test[35581:2441346] -[NSTaggedPointerString appendString:]: unrecognized selector sent to instance 0xa00206f6c6c65686
2017-11-29 14:16:07.087851+0800 test[35581:2441346] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSTaggedPointerString appendString:]: unrecognized selector sent to instance 0xa00206f6c6c65686'
说明:我们发现在执行[stringStr2 appendString:@"你好世界"];的时候报错了,这说明此处声明的copy只是浅拷贝,我们虽然声明了NSMutableString *stringStr2,是可变字符串,实际上它指向的还是NSString,NSString是不可变的,所以操作stringStr2会报错。
我们把:
NSMutableString *stringStr2 = (NSMutableString *)self.stringStr;
换成深拷贝
NSMutableString *stringStr2 = [(NSMutableString *)self.stringStr mutableCopy];
输出结果:
2017-11-29 14:29:03.616800+0800 test[35695:2462671] self.stringStr:hello
2017-11-29 14:29:06.005029+0800 test[35695:2462671] stringStr2:hello
2017-11-29 14:29:06.005183+0800 test[35695:2462671] stringStr2:hello 你好世界
2017-11-29 14:29:06.005292+0800 test[35695:2462671] self.stringStr:hello
我们发现就可以赋值了,而且从输出结果来看stringStr2的修改并没有影响stringStr,
总结:
@property声明的NSString(或NSArray,NSDictionary)使用copy关键字会避免以下问题:
1 如果把它赋值给一个可变字符串,如果可变字符串修改,会报错,这样相当于通知你,这个操作会有问题。总比不告诉你,然后偷偷把你改了强吧(strong)
2 如果采用深拷贝,那么即使把它赋值给一个可变字符串,如果可变字符串修改,也不会影响你。
3 NSArray,NSDictionary的原理同NSString一样。
网友评论