感谢:http://my.oschina.net/aofe/blog/266677
一、概念
1. 目的:在改变原有对象的时候,不会改变新对象的值
2. Copy 字面上面的意思是拷贝,是一个产生副本的过程。
3. 特点:
1). 修改源文件的内容,不会影响副本文件;
2). 修改副本文件的内容,不会影响源文件;
4. 如何使用Copy功能?
一个对象可以调用copy或MutableCopy方法来创建一个副本对象。
1). Copy:创建的是不可变副本(NSString、NSArray....)
2). MutableCopy:创建的是可变副本(NSMutableString、NSMutableArray....)
5. 使用copy的前提
1). copy:需要遵守NSCopying协议,实现copyWithZone: 方法;
@protocol NSCopying
- (id)copyWithZone:(NSZone *)zone;
@end
2). MutableCopy::需要遵守NSMutableCopyint协议,实现MutableCopyWithZone: 方法;
@protocol NSMutableCopying
- (id)mutableCopyWithZone:(NSZone *)zone;
@end
6. 内存管理
1). 深拷贝:内容拷贝,会产生新的对象,所以源对象的计数器不变 >>> 对象拷贝
特点: 源对象和副本对象是两个不同的对象;
源对象计数器不变,新对象计数器为1(是因为新产生的);
本质: 产生了新的对象
2). 浅拷贝: 指针拷贝(不是将地址赋值给另外一个)不产生新的对象,所以源对象计数器+1 >>> 指针拷贝(因为对象本身不可以变,所以没有必要在创建一个对象)
特点:源对象与新对象是同一对象;
源对象(副本对象)引用计数器+1,相当于做了一次retain操作;
本质: 没有产生了新的对象
关系图如下:
二、NSString 与 copy
1. NSString 与 MutableCopy (深拷贝)
void stringMutableCopy() {
// 不可变
NSString *string = [[NSString alloc] initWithFormat:@"age is %i", 10];
// 可变,产生一个新对象,计数器+1,源对象的计数器不变
NSMutableString *str = [string mutableCopy];
// 由不可变转变为可变 不是同一对象了
NSLog(@"str:%zi", [str retainCount]);
NSLog(@"string:%zi", [string retainCount]);
// 验证是否为同一对象
NSLog(@"string == str ?: %i", string == str);
// 改变副本看看源对象是否变化
[str appendString:@"haha"];
NSLog(@"string:%@", string);
NSLog(@"str:%@", str);
// 释放
[string release];
[str release];
}
2. NSString 与 Copy(浅拷贝)
void stringCopy() {
// 不可变
NSString *string = [[NSString alloc] initWithFormat:@"age is %i", 10];
// 不可变,
// 没有产生新的对象。(这是由于源对象本身不可变,所以副本是不可变的)
NSString *str = [string copy];
// 打印计数器
NSLog(@"str:%zi", [str retainCount]);
NSLog(@"string:%zi", [string retainCount]);
// 验证是否为同一对象
NSLog(@"string == str ?: %i", string == str);
// 改变副本看看源对象是否变化
//[str appendString:@"haha"];
NSLog(@"string:%@", string);
NSLog(@"str:%@", str);
[str release];
[string release];
}
3. NSMutableString 与 MutableCopy(深拷贝)
void mutableStringMutableCopy() {
// 可变
NSMutableString *string = [NSMutableString stringWithFormat:@"age is %i", 10];
// 这个属于深拷贝
// 可变
NSMutableString *str = [string mutableCopy];
// 验证是否为同一对象
NSLog(@"string == str ?: %i", string == str);
// 释放
[str release];
[string release];
}
3. NSMutableString 与 Copy(深拷贝)
void mutableStringCopy() {
// 可变
NSMutableString *string = [NSMutableString stringWithFormat:@"age is %i", 10];
// 这个属于深拷贝
// 不可变
NSString *str = [string copy];
// 验证是否为同一对象
NSLog(@"string == str ?: %i", string == str);
// 释放
[str release];
[string release];
}
三、对象拷贝实例
对象拷贝实例必须要注意的问题:
1). 必须要实现NSCopying协议;
2). 需要重写-(id)copyWithZone:(NSZone *)zone 方法;
3). 代码中self class的引用 ()
01. GoodStudent.h
#import "Student.h"
@interface GoodStudent : Student
@property (nonatomic, assign) int age;
+(id)goodStudentWithName:(NSString *)name withAge:(int)age;
@end
02. GoodStudent.m
#import "GoodStudent.h"
@implementation GoodStudent
+(id)goodStudentWithName:(NSString *)name withAge:(int)age
{
GoodStudent *stu = [super studentWithName:name];
stu.age = age;
return stu;
}
-(id)copyWithZone:(NSZone *)zone
{
GoodStudent *copy = [super copyWithZone:zone];
copy.age = self.age;
return copy;
}
-(NSString *)description
{
return [NSString stringWithFormat:@"%@-%i", self.name, self.age];
}
@end
03. Student.h
#import <Foundation/Foundation.h>
@interface Student : NSObject <NSCopying>
@property (nonatomic, copy) NSString *name;
+(id)studentWithName:(NSString*)name;
@end
04. Student.m
#import "Student.h"
@implementation Student
+(id)studentWithName:(NSString *)name
{
Student *stu = [[[[self class] alloc] init] autorelease];
stu.name = name;
return stu;
}
- (id)copyWithZone:(NSZone *)zone
{
Student *copy = [[self class] allocWithZone:zone];
copy.name = self.name;
return copy;
}
-(NSString *)description
{
return [NSString stringWithFormat:@"%@", self.name];
}
-(void)dealloc
{
[_name release];
[super dealloc];
}
@end
05.main
#import <Foundation/Foundation.h>
#import "GoodStudent.h"
void test1()
{
Student *stu = [Student studentWithName:@"name1"];
Student *stu1 = [stu copy];
NSLog(@"%@", stu);
NSLog(@"%@", stu1);
}
void test2()
{
GoodStudent *stu1 = [GoodStudent goodStudentWithName:@"name1" withAge:10];
GoodStudent *stu2 = [stu1 copy];
NSLog(@"%@", stu1);
NSLog(@"%@", stu2);
}
int main(int argc, const char * argv[])
{
@autoreleasepool {
test2();
}
return 0;
}
四、@property内存管理策略的选择
1. 非ARC
1). copy: 只用于NSString/block;
2). retain: 除NSString/block以外的oc对象;
3). assign:基本数据类型、枚举、结构体(非OC对象),当两个对象相互引用,一端用retain,一端用assign;
2. ARC
1). copy: 只用于NSString/block;
2). strong: 除NSString/block以外的oc对象;
2). weak: 当两个对象相互引用,一端用strong,一端用weak;
3). assign:基本数据类型、枚举、结构体(非OC对象);
感谢:http://my.oschina.net/aofe/blog/266677