[OC Foundation框架 - 17] copy语法

一个对象使用copy或mutableCopy方法可以创建对象的副本

1.copy
需要实现NSCopying协议
创建出来的是 不可变副本,如NSString, NSArray, NSDictionary
 
(1)不可变对象调用copy  (NSSring除外)
不会产生新的对象,而是返回对象本身,相当于retain,计数器+1
属于浅拷贝
 
复制代码
 1         NSArray *arr1 = [NSArray arrayWithObjects:@"张三", @"李四", nil];

 2         NSLog(@"arr1.addr: %p", arr1); // 0x1002052b0

 3         NSLog(@"arr1.retainCount: %ld", arr1.retainCount); // 1

 4 

 5        

 6         NSArray *arr2 = [arr1 copy];

 7         NSLog(@"arr1.addr: %p", arr1); // 0x1002052b0

 8         NSLog(@"arr1.retainCount: %ld", arr1.retainCount); // 2  <-- 浅拷贝,相当于retain, retainCount+1

 9         NSLog(@"arr2.addr: %p", arr2); //0x1002052b0 <-- 浅拷贝,依旧指向同一个对象

10         NSLog(@"arr2.retainCount: %ld", arr2.retainCount); // 2 <-- 浅拷贝,还是原来对象的retainCount
复制代码
 
(2)可变对象调用copy (NSMutableString会拷贝出一个NSString”常量对象")
返回一个不可变对象,但是不是原来的对象,属于深拷贝
复制代码
 1         NSMutableArray *arr1 = [NSMutableArray array];

 2         [arr1 addObject:@"123"];

 3         [arr1 addObject:@"abc"];

 4         NSLog(@"arr1.addr: %p", arr1); // 0x100204840

 5         NSLog(@"arr1.retainCount: %ld", arr1.retainCount); // 1

 6        

 7        

 8         NSMutableArray *arr2 = [arr1 copy];

 9         NSLog(@"arr1.addr: %p", arr1); // 0x100204840

10         NSLog(@"arr1.retainCount: %ld", arr1.retainCount); // 1 <-- 深拷贝,原来的对象retainCount保持

11         NSLog(@"arr2.addr: %p", arr2); // 0x100300000 <-- 深拷贝,开辟了新的内存空间,拷贝出来的实际对象是NSArray

12         NSLog(@"arr2.retainCount: %ld", arr2.retainCount); // 1 <-- 深拷贝,新的对象retainCount独立
复制代码
 
(3)重点: NSString的特殊性
由于使用了 @“” 进行初始化,数据存放在了常量池
 
因为NSString指向字符串常量,系统不会收回,也不会对其作引用计数,即使我们对NSString变量如何retain或release,retainCount都是-1 (无符号最大值)
复制代码
 1         NSString *str1 = [[NSString alloc] initWithString:@"abc"];

 2         NSLog(@"str1.addr: %p", str1); // 0x100001030

 3         NSLog(@"str1.retainCount: %ld", str1.retainCount); // -1 <-- 字符串常量存在常量池,不使用堆内存

 4        

 5         NSString *str2 = [str1 copy];

 6         NSLog(@"str1.addr: %p", str1); // 0x100001030

 7         NSLog(@"str1.retainCount: %ld", str1.retainCount); // -1 <-- 无论是copy, retain, release操作都不会改变retianCount

 8         NSLog(@"str2.addr: %p", str2); // 0x100001030 <-- 拷贝之后的变量依旧指向原来的常量

 9         NSLog(@"str2.retainCount: %ld", str2.retainCount); // -1 <-- 原来常量的retainCount

10        

11         [str1 retain];

12         NSLog(@"after retain -> str1.retainCount: %ld", str1.retainCount); // -1 <-- 无论是copy, retain, release操作都不会改变retianCount

13         [str2 release];

14         NSLog(@"after release -> str2.retainCount: %ld", str2.retainCount); // -1 <-- 无论是copy, retain, release操作都不会改变retianCount
复制代码
 
要使一个NSString变量也有retainCount:
就要是指向另外一个”NSString” 对象,而不是 字符串常量
1         // 先创建出一个NSString对象,再用另一个指向

2         NSString *str1 = [NSString stringWithFormat:@"abc"];

3         NSLog(@"%ld", str1.retainCount); // -1

4         NSString *str2 = [NSString stringWithString:str1];

5         NSLog(@"%ld", str2.retainCount); // 1
 
(4)copy出来的是不可变对象,如NSMutableString调用copy创建出来的实际是NSString
复制代码
 1         // 这里不能使用 NSMutableString *mstr1 = @"abc", 或者在延迟赋值 mstr1 = @"abc"; 否则同样指向常量池

 2         NSMutableString *mstr1 = [[NSMutableString alloc] initWithString:@"abc"];

 3         NSLog(@"mstr1.addr: %p", mstr1); // 0x100404990

 4         NSLog(@"mstr1.retainCount: %ld", mstr1.retainCount); // 1

 5 

 6 

 7         NSMutableString *mstr2 = [mstr1 copy];

 8         NSLog(@"mstr1.addr: %p", mstr1); // 0x100404990

 9         NSLog(@"mstr1.retainCount: %ld", mstr1.retainCount); // 1 <-- 深拷贝,原来的对象retainCount保持

10         NSLog(@"mstr2.addr: %p", mstr2); // 0x63626135 <-- 深拷贝,开辟了新的内存空间,但是指向的实际是一个字符串常量

11         NSLog(@"mstr2.retainCount: %ld", mstr2.retainCount); // -1 <-- 因为其实拷贝出来的是一个字符串常量
复制代码

 

2.mutableCopy
需要实现NSMutableCopying协议
创建的是可变副本,如NSMutableString, NSMutableArray, NSMutableDictionary
 
(1)不可变对象调用mutableCopy
产生一个新的对象,新旧对象的计数器独立,不会互相干扰,属于深拷贝
复制代码
1         NSString *str1 = [[NSString alloc] initWithString:@"abc"];

2         NSLog(@"str1.addr: %p", str1); // 0x100001030

3         NSLog(@"str1.retainCount: %ld", str1.retainCount); // -1 <-- 字符串常量存在常量池,不使用堆内存

4 

5         NSMutableString *mstr2 = [str1 mutableCopy]; // mutableCopy 出来的是一个 NSMutableString 对象

6         NSLog(@"str1.addr: %p", str1); // 0x100001030

7         NSLog(@"str1.retainCount: %ld", str1.retainCount); // -1 <-- 对于字符串常量, 无论是copy, retain, release操作都不会改变retianCount

8         NSLog(@"mstr2.addr: %p", mstr2); // 0x100106460 <-- 深拷贝,开辟新的空间

9         NSLog(@"mstr2.retainCount: %ld", mstr2.retainCount); // 1 <-- 由于是NSMutableString对象,retainCount == 1
复制代码
 
(2)可变对象调用mutableCopy
产生一个新的对象,新旧对象的计数器独立,不会互相干扰,属于深拷贝
复制代码
1         NSMutableString *mstr1 = [[NSMutableString alloc] initWithString:@"abc"];

2         NSLog(@"mstr1.addr: %p", mstr1); // 0x100402910

3         NSLog(@"mstr1.retainCount: %ld", mstr1.retainCount); // 1

4 

5         NSMutableString *mstr2 = [mstr1 mutableCopy]; // mutableCopy 出来的是一个 NSMutableString 对象

6         NSLog(@"mstr1.addr: %p", mstr1); // 0x100402910

7         NSLog(@"mstr1.retainCount: %ld", mstr1.retainCount); // 1

8         NSLog(@"mstr2.addr: %p", mstr2); // 0x100300e90 <-- 深拷贝,开辟新的空间

9         NSLog(@"mstr2.retainCount: %ld", mstr2.retainCount); // 1
复制代码
 
3.自定义类的copy
1 @interface Student : NSObject

2 

3 //copy代表setter会release旧对象,copy新对象

4 @property (nonatomic, copy) NSString *name;

5 

6 @end
 
传入外部NSMutableString对象到student的setter,当外部对象改变的时候,不会改变student中copy来的对象
如果使用retain或者assign,就会影响,因为指向的是同一个对象
==>传入NSMutableString时(成员变量为NSString),一般使用copy策略,其他使用retain
 
(1)实现<NSCopying>
(2)实现 - (id) copyWithZone:(NSZone *) zone
1 - (id)copyWithZone: (NSZone *) zone

2 {

3      Student *stu = [[Student allocWithZone:zone] init];

4      stu.name = self.name;

5      return stu;

6 }

 

你可能感兴趣的:(copy)