最近和一个朋友一起做外包项目,发现他所有的NSString属性都是用strong来作为关键字的。但其实我们更推荐用copy来修饰一个immutable对象,用strong来修饰一个mutable对象,这也算是面试中很常见的问题吧。

首先,为什么NSString要使用copy,用strong会有什么样的问题?

我觉得回答这个问题最有力的一句话就是:因为父类指针可以指向子类对象。使用copy的话,可以不管传入的对象是mutable还是immutable的,都可以保证自己持有的是immutable的副本。口说无凭,让我们举个简单的🌰:

@property (nonatomic, copy) NSString *testStr;

NSMutableString *test = [[NSMutableString alloc] initWithString:@"123"];

self.testStr = test;

NSLog(@"self.testStr:%@",self.testStr);

[test appendString:@"tt"];

NSLog(@"self.testStr:%@",self.testStr);

打印结果:

MyTestProject[57848:1228549] self.testStr:123

MyTestProject[57848:1228549] self.testStr:123

可以看到,testStr并不受test字符串的变化而影响。下面我们稍微改一下,把testStr的声明改成strong,其他部分不变,打印结果:

MyTestProject[57881:1232402] self.testStr:123

MyTestProject[57881:1232402] self.testStr:123tt

事实上,这里的self.testStr和test都指向同一个地址,而没有新开辟一块空间,自然会跟随着变化了。而我们一般声明为NSString,是不希望它在我们不察觉的情况下被修改的,所以还是使用copy更为合理。

多说一句,如果在赋值的时候使用_testStr而不是self.testStr呢?答案是无论testStr声明为strong还是copy,都会随着test字符串变动而变动。而至于为什么,这就是另外一个问题了,属性和实例变量的区别。总之建议如果不是在init和dealloc中的时候,还是尽量使用self.来享受苹果带给我们的便利吧。

那么为什么immutable对象要使用strong呢?使用copy会有什么样的问题?

这个就涉及到深拷贝浅拷贝的问题了,网上有关这个的博客太多了,还是不赘述了。我还是只举个🌰吧:

@property (nonatomic, copy) NSMutableString *testStr;

NSString *test = @"123";

self.testStr = test;

[self.testStr appendString:@"tt"];

运行后我们会看到,程序直接crash掉了,log是:'Attempt to mutate immutable object with appendString:'。事实上,编译器在我们编码的时候也会给我们提示:incompatible pointer types assigning to "NSMutableString *" to "NSString *"。

之所以会crash,是因为我们在赋值的时候,copy自动帮我们做了一次深拷贝,返回了一个immutable的对象,也就是NSString对象,而NSString对象没有appendString方法,自然就crash掉了。

2025-06-06 00:03:15