字符串的copy和strong,数组的copy

avatar
作者
猴君
阅读量:0

先说字符串.假设对象持有如下两个属性

@property (nonatomic, strong) NSString *strStrong;

@property (nonatomic, copy) NSString *strCopy;

然后做如下操作1

```

NSMutableString *str = [NSMutableString stringWithFormat:@"%@",@"3333"];

     self.strCopy= str;

    self.strStrong= str;

    NSLog(@"\n%p\n%p\n%p",str,self.strStrong,self.strCopy);

```

得到的结果如下

0x6000038e9b30

0x6000038e9b30

0xcefcc275fcf19ade

也就是说对于可变字符串,关键字strong只是引用计数器加1,strong后的指针指向原来的存储空间。copy后是新开一个存储空间。而且很重要的一点,copy的对象类型是不可变字符串,就是NSString类型。那strong不用说啦,还是可变类型。

那么对于NSString,使用copy和strong用什么不同吗?请看下面例子

NSString*str =@"33";

self.strCopy= str;

self.strStrong= str;

   NSLog(@"\n%p\n%p\n%p",str,self.strStrong,self.strCopy);

结果如下

0x107cd8078

0x107cd8078

0x107cd8078

就是说,对于NSString,不管使用copy还是strong,都只是引用计数器加1。不会开辟新的内存空间。而且类型都是NSString类型的。就是说对于NSString类型,你的关键字是copy还是strong,影响不是那么大。但是考虑到多态特性,NSString类型可能指向NSMutableString类型的对象,建议字符串类型还是使用copy吧。

总结如下:使用copy之后,对于不可变字符串来说,不会新开内存空间,跟strong作用一样。但是对于可变字符串来说,copy是新开一个内存空间的,且新创建的对象是不可变字符串,strong是引用计数器加1,类型不变。

2.再说下数组

    NSArray*arr =@[@"23",@"45"];

    NSArray*arr2 = [arr copy];

    NSArray*arr3 = [arr mutableCopy];

    NSLog(@"%p\n%p\n%p",arr,arr2,arr3);

对应的值如下

0x6000036e7220

0x6000036e7220

0x6000038e9800

说明,不可变数组使用copy只是浅拷贝,就是原对象引用计数器加1,在内存中没有新开辟一个空间。而mutableCopy,原对象引用计数器不累加,但是新开了一个内存空间,是个深拷贝。而且copy后的类型还是不可变数组,mutableCopy之后的对象类型是可变数组

那么对于可变数组的copy和mutableCopy又是怎么样?请看下面的例子

    NSMutableArray *arrM = [NSMutableArray arrayWithObjects:@"33",@"55", nil];

    NSArray*arrM2 = [arrM copy];

    NSArray*arrM3 = [arrM mutableCopy];

    NSLog(@"%p\n%p\n%p",arrM,arrM2,arrM3);

对应的值如下

0x6000038e9b00

0x6000036e7160

0x6000038e9860

说明可变数组不管使用copy还是mutableCopy,都会新开一个内存空间。而且copy后的对象类型是不可变数组,mutableCopy之后的是可变数组。也就是说可变数组的的拷贝都是深拷贝

总结如下:对于不可变数组,copy只是引用计数器加1,不开辟新的内存空间,跟strong作用一样。mutableCopy开辟新的内存空间。对于可变数组,不管使用copy还是mutableCopy,都会新开一个内存空间。而且copy后的对象类型是不可变数组,mutableCopy之后的是可变数组。

对于字符串和数组使用copy的共同特点是,不可变类的使用copy只是引用计数器加1;可变类型的使用copy会新开一个内存空间,但是类型是不可变类型。

strong对于可变数组只是引用计数器加1.有兴趣的朋友可以在MRC环境下验证。

属性修饰符字符串为什么用copy而不用strong

在Objective-C中,属性修饰符选择copy而不是strong,主要是基于几个关键考虑因素,特别是当属性类型为不可变对象(如NSStringNSArrayNSDictionary等)时。以下是几个主要原因:

  1. 防止可变对象被意外修改:当你将一个可变对象(如NSMutableString)赋值给一个被声明为不可变类型(如NSString)的属性时,如果使用strong修饰符,那么原始的可变对象仍然可以被修改,这可能会导致不可预见的行为或错误。使用copy修饰符可以确保属性接收的是原始对象的一个不可变副本,因此即使原始对象被修改,属性的值也不会受到影响。

  2. 符合不可变语义:对于被设计为不可变的类(如NSString),使用copy修饰符更符合其不可变的语义。这有助于维护类的封装性和不变性,使得类的使用者不会意外地修改到类的内部状态。

  3. 线程安全:在某些情况下,使用copy可以提高线程安全性。虽然strongcopy本身并不直接解决线程同步问题,但当你将属性设置为copy时,每个线程都会获得其自己的对象副本,从而减少了线程间共享数据的风险。

  4. 性能考虑:虽然copy操作可能会比简单的赋值(strong)更耗时,因为它涉及到对象的复制,但在许多情况下,这种性能开销是可以接受的,并且换来了更高的数据完整性和安全性。此外,对于不可变对象来说,由于它们的内容在创建后不会改变,因此它们的copy操作通常是非常高效的(例如,NSStringcopy方法可能只是简单地返回一个指向相同数据的指针)。

需要注意的是,对于可变对象类型(如NSMutableStringNSMutableArray等),你应该使用strong修饰符,因为copy将创建一个不可变的副本,这可能会与你的设计意图相悖。

最后,选择copy还是strong应该基于你的具体需求和属性的预期用途。在大多数情况下,对于不可变对象类型,使用copy是一个更安全、更可靠的选择。

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!