在iOS开发中, 我们往往会使用一些文字描述, 如论外界如何改变, 描述都不改变, 此时我们就会使用到copy或者mutableCopy
要是是使用copy/mutableCopy, 必须要遵守NSCoping/NSMutableCoping协议, 并且实现协议中的方法
copy/mutableCopy语法的本质是:产生新对象,当改变新对像时,不改变源对象
1>调用copy返回的是不可变的,调用mutableCopy返回的时可变的
2>不可变类型的调用的copy方法,是浅拷贝(指针拷贝,地址拷贝),新对象和源对象指向的是同一对象,源对象的计数器+1变成2
3>其他情况下,都是产生新对象,源对象的计数器不变,新对象的计数器置为1
1.系统自带类的拷贝
#pragma mark - NSString的copy(浅拷贝,指针拷贝,地址拷贝)
//不可变copy---->不可变,只是地址(指针)的拷贝,新对象和源对象指向同一对象,源对象的计数器+1变成2
NSString *string = [[NSString alloc] initWithFormat:@"age is %i", 10];
NSLog(@"%zi", [string retainCount]);//
NSString *str = [string copy];// 返回不变的,为了性能着想, 干脆返回源对像, 相当于retain
NSLog(@"%zi", [str retainCount]);
//产看是否产生新的对象
BOOL isEqual = (str==string);
NSLog(@"isEqual = %i", isEqual);
NSLog(@"string = %p, str = %p", string, str);//通过打印内存地址诶查看, 内存地址相等
[str release];
[string release];
#pragma mark - NSString的MutabelCopy(深拷贝)对象拷贝
//深拷贝(对象拷贝),源对象计数器不变, 新计数器置1
NSString *string = [[NSString alloc] initWithFormat:@"age is %i", 10];
NSLog(@"%zi", string.retainCount); //1
NSMutableString *str = [string mutableCopy];
NSLog(@"%zi", str.retainCount); //1
[str appendString:@" abcd"];
BOOL isEqual = (str==string);
NSLog(@"isEqual = %i", isEqual);// 0
NSLog(@"string = %@", string); //string = age is 10
NSLog(@"str = %@", str); //str = age is 10 abcd
#pragma mark - NSMutableString的copy(深拷贝)
NSMutableString *string = [[NSMutableString alloc] initWithFormat:@"age is %i", 10];
NSLog(@"%zi", string.retainCount); //1
NSString *str = [string copy];
NSLog(@"%zi", str.retainCount); //1
[string appendString:@" abcd"];
NSLog(@"string = %@", string); //string = age is 10 abcd
NSLog(@"str = %@", str); //str = age is 10
#pragma mark - NSMutableString的MutableCopy(深拷贝)
NSMutableString *string = [[NSMutableString alloc] initWithFormat:@"age is %i", 10];
NSLog(@"%zi", string.retainCount);
NSMutableString *str = [string mutableCopy];
NSLog(@"%zi", str.retainCount);
[string appendString:@" abcd"];
[str appendString:@"lllllll"];
NSLog(@"string = %@", string); //string = age is 10 abcd
NSLog(@"str = %@", str); //str = age is 10lllllll
2.自定义对象的拷贝
1>
//Person类
//Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject <NSCopying, NSMutableCopying>
//copy代表set方法会release就对象,copy新对象
//修改外边的变量, 并不会影响到内部的成员变量
//建议:NSString一般用copy策略, 其他对象一般用retain
@property (nonatomic, copy, readwrite) NSString *name;
+ (instancetype)personWithName:(NSString *)name;
- (instancetype)initWithName:(NSString *)name;
@end
#import "Person.h"
@implementation Person
- (id)copyWithZone:(NSZone *)zone{
Person *copy = [[[self class] allocWithZone:zone] init];
//拷贝属性
copy.name = self.name;// 等价于copy.name = [self.name copy];
/*
按道理只需要这样copy.name = [self.name copy];就能实现深拷贝,
copy.name = [self.name copy];
a:如果是Foundation框架里的不可变对象,就是Array,NSString等创建的对象,直接用copy来拷贝相当于retain,也就是属性还是同一个;
b:如果是用mutableCopy来拷贝,不管是可变还是不可变对象,属性神马的都直接拷贝了一份,即真正意义上得拷贝,它拷贝出来的对象统统都是可变的;
c:如果是可变对象,我们用copy也能实现真正意义上的拷贝,但是拷贝出来的对象是不可变的。
*/
return copy;
}
-(id)mutableCopyWithZone:(NSZone *)zone{
Person *mutableCopy = [[[self class] allocWithZone:zone] init];
mutableCopy.name = [self.name mutableCopy];
return mutableCopy;
}
-(instancetype)initWithName:(NSString *)name{
_name = name;
return self;
}
+(instancetype)personWithName:(NSString *)name{
Person *p = [[Person alloc] init];
p.name = name;
return p;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"%@:[name = %@]", [self class], self.name];
}
// copy 对象的地址不同, 但是属性的地址相同
NSString *str = [[NSString alloc] initWithFormat:@"zhaofei is %i", 10];
Person *person = [Person personWithName:str];
NSLog(@"person = %p", person);
NSLog(@"person.name = %p", person.name);
NSLog(@"%zi", person.retainCount);// 计数器为2
NSLog(@"%zi", person.name.retainCount);// 计数器为1
// NSLog(@"person.age = %p", person.age);
Person *p = [person copy];
// p.name = @"aksdlk";
NSLog(@"p = %p", p);
NSLog(@"p.name = %p", p.name);
NSLog(@"%zi", p.retainCount);// 计数器为1
NSLog(@"%zi", p.name.retainCount);// 计数器为4
NSLog(@"%@", person);
NSLog(@"%@", p);
#pragma mark - person 的mutableCopy
// 需要在mutableCopyZone方法里将属性用mutbaleCopy方式进行拷贝
//对象的地址不同, 但是属性的地址不同
<span style="white-space:pre"> </span>NSString *str = [[NSString alloc] initWithFormat:@"zhaofei is %i", 10];
Person *person = [Person personWithName:str];
NSLog(@"person = %p", person);
NSLog(@"person.name = %p", person.name);
NSLog(@"%zi", person.retainCount);// 计数器为1
Person *p = [person mutableCopy];
NSLog(@"p = %p", p);
NSLog(@"p.name = %p", p.name);
NSLog(@"%zi", p.retainCount);// 计数器为1
str = @"kaslkdadkasd";//不会修改对象里面的属性值
NSLog(@"%@", person);
NSLog(@"%@", p);
3. 定义一个Student类, 继承Person类, 并且声明一些Person中没有的属性的时候, 如果要使用copy/mutableCopy, 就应该重写父类Person的- (instancetype)copyWithZone:(NSZone *zone) 和 - (instancetype)mutableCopyWithZone:(NSZone *)zone方法, 并且在方法要拷贝对象的属性