关于 NSString 使用 copy 和 strong 修饰的区别

851 阅读3分钟
原文链接: www.jianshu.com

第一种情况: 使用 copy 修饰

// 代码片段1
// Person.h
@interface Person : NSObject
@property (nonatomic, copy) NSString *lastName;
@end

// Person.m
@implementation Person
- (instancetype)init {
    self = [super init];
    if (self) {
        _lastName = @"name";
    }
    return self;
}
@end

// main.m
int main(int argc, const char * argv[]) {
    Person *p1 = [[Person alloc] init];
    NSLog(@"lastname = %@, lastname address = %p", p1.lastName, p1.lastName);

    NSMutableString *newLastName = [[NSMutableString alloc] initWithString:@"newname"];
    NSLog(@"newLastName = %@, newLastName address = %p", newLastName, newLastName);

    p1.lastName = newLastName;
    NSLog(@"lastname = %@, lastname address = %p", p1.lastName, p1.lastName);

    return 0;
}

以上代码执行后的结果如下:

lastname = name, lastname address = 0x100001078
newLastName = newname, newLastName address = 0x1003031e0
lastname = newname, lastname address = 0x100303720

从以上打印的结果可以看到,第一次打印的 lastname address和第二次打印的 lastname address 结果并不相同,同时 newLastName address 和第二次打印的 lastname address 也不相同,说明执行 p1.lastName = newLastName 之后 p1.lastName 指向了一块全新的内存空间,这就是 copy 的作用:重新开辟一块内存空间存放 newLastName 的值。

改变一: 修改 main 方法中的代码,在 return 0 之前添加以下代码

[newLastName appendString:@"abc"];
NSLog(@"lastname = %@, lastname address = %p", p1.lastName, p1.lastName);

newLastName 的值变成了 newnameabc,但是 p1.lastName 的值没有任何变化。这很简单,根据 copy 的作用 p1.lastNamenewLastName 指向完全不同的地址,对 newLastName 做的改变自然不会反映在 p1.lastName 上。

第二种情况: 使用 strong 修饰

将代码:

@property (nonatomic, copy) NSString *lastName;

修改为:

@property (nonatomic, strong) NSString *lastName;

执行代码片段1之后的结果如下:

lastname = name, lastname address = 0x100001068
newLastName = newname, newLastName address = 0x100202e00
lastname = newname, lastname address = 0x100202e00

从以上结果中发现第一次打印的 lastname address 和第二次打印的 lastname address 指向不同的内存,但是第二次打印的 lastname addressnewLastName address 相同,说明,与 copy 不同的是,strong 并没有开辟一块新的内存空间,而是直接将 lastname 指向了 newLastName

改变一: 修改 main 方法中的代码,在 return 0 之前添加以下代码

[newLastName appendString:@"abc"];
NSLog(@"newLastName = %@, newLastName address = %p", newLastName, newLastName);
NSLog(@"lastname = %@, lastname address = %p", p1.lastName, p1.lastName);

打印结果如下:

newLastName = newnameabc, newLastName address = 0x100202e00
lastname = newnameabc, lastname address = 0x100202e00

因为 newLastNamep1.lastname 指向同一个内存,对 newLastName 的改变也就改变了 p1.lastname。但是 lastname 属性是不可变的 NSString 类型,而在这里却发生了改变。

另外

如果有以下代码:

@property (nonatomic, copy) NSMutableString *mString;

如果在未来给 mString 重新赋了一个新值,则会产生一个不可变的副本,此时想在 mString 上调用 NSMutableString 的相关方法是不行的。

结论

copy 修饰的 NSString 如果在无意中被一个 NSMutableString 类型的变量赋值,原先的 NSString 会被 copy 一份用来存储 NSMutableString 的值,万一 NSMutableString 的值被修改,不会影响到 NSString 的值,这能体现 NSString 作为不可变类型的性质。

strong 修饰的 NSString 如果在无意中被一个 NSMutableString 类型的变量赋值, NSString 不会被拷贝,一旦 NSMutableString 的值被修改,NSString 的值也就发生了改变,这与 NSString 作为不可变类型相违背。

当然如果 NSString 被一个 NSString 赋值,copy 的效果与 strong 的效果是一样的,直接改了就是。

以上的结论同样适用于 NSArrayNSDictionary