---------- IOS培训、java培训、期待与您交流! ----------
一个对象使用copy 与 mutableCopy可以创建一个对象的副本
copy--需要实现NSCopying协议,创建的是不可变副本(如NSString,NSArray,NSDictionary)
mutableCopy---需要实现NSMutableCopying协议,创建的是可变副本(如NSMutableString,NSMutableArray,NSMutableDictionary)
用一个专业术语来描述拷贝
深拷贝:内容拷贝,源对象和副本指向的不是两个对象。源对象引用计数器不变,副本计数器设置为1。
浅拷贝:指针拷贝,源对象和副本指向的是同一个对象。对象引用计数器加1,相当于做了一次retain操作。
只有不可变对象创建不可变副本的时候才是浅拷贝,其它任何时候都是深拷贝。---即,当对象不同的时候就一定是深拷贝。
用图来描述什么是浅拷贝;
用图来演示深拷贝;
copy语法的目的:改变副本的时候,不会影响到源对象
// 深拷贝:内容拷贝,会产生新的对象。新对象计数器置为1,源对象计数器不变。
void stringMutableCopy() {
// string:1
NSString *string = [[NSString alloc] initWithFormat:@"age is %i", 10];
// 产生了一个新的对象,计数器为1。源对象的计数器不变。
// str:1
// string:1
NSMutableString *str = [string mutableCopy];
//NSLog(@"str:%zi", [str retainCount]);
//NSLog(@"string:%zi", [string retainCount]);
// str和string不是相同对象
// NSLog(@"%i", str == string);
[str appendString:@" abcd"];
NSLog(@"string:%@", string);
NSLog(@"str:%@", str);
// str:0
[str release];
// string:0
[string release];
}
// 只有一种情况是浅拷贝:不可变对象调用copy方法时
// 浅拷贝:指针拷贝,不会产生新的对象。源对象计数器+1。
void stringCopy() {
NSString *string = [[NSString alloc] initWithFormat:@"age is %i", 10];
NSLog(@"%zi", [string retainCount]);
// copy产生的是不可变副本,由于源对象本身就不可变,所以为了性能着想,copy会直接返回源对象本身
// 源对象计数器会+1
// 在浅拷贝情况下,copy其实就相当于retain
NSString *str = [string copy];
NSLog(@"%zi", [string retainCount]);
// NSLog(@"%i", str == string);
[str release];
[string release];
}
如果我们定义一个student类 用来演示对象的copy方法
#import <Foundation/Foundation.h>
@interface Student : NSObject <NSCopying>
// copy代表set方法会release旧对象、copy新对象
// 修改外面的变量,并不会影响到内部的成员变量
// 建议:NSString一般用copy策略,其他对象一般用retain
@property (nonatomic, copy) NSString *name;
+ (id)studentWithName:(NSString *)name;
@end
#import "Student.h"
@implementation Student
+ (id)studentWithName:(NSString *)name {
// 这里最好写[self class]
Student *stu = [[[[self class] alloc] init] autorelease];
stu.name = name;
return stu;
}
- (void)dealloc {
[_name release];
[super dealloc];
}
#pragma mark description方法内部不能打印self,不然会造成死循环
- (NSString *)description {
return [NSString stringWithFormat:@"[name=%@]", _name];
}
#pragma mark copying协议的方法
// 这里创建的副本对象不要求释放
- (id)copyWithZone:(NSZone *)zone {
Student *copy = [[[self class] allocWithZone:zone] init];
// 拷贝名字给副本对象
copy.name = self.name;
return copy;
}
@end
void studentCopy() {
Student *stu1 = [Student studentWithName:@"stu1"];
Student *stu2 = [stu1 copy];
stu2.name = @"stu2";
NSLog(@"stu1:%@", stu1);
NSLog(@"stu2:%@", stu2);
[stu2 release];
}
- (id)copyWithZone:(NSZone *)zone {
// 一定要调用父类的方法
GoodStudent *copy = [super copyWithZone:zone];
copy.age = self.age;
return copy;
}
void goodStudentCopy() {
GoodStudent *stu1 = [GoodStudent goodStudentWithAge:10 name:@"good1"];
GoodStudent *stu2 = [stu1 copy];
stu2.name = @"good2";
stu2.age = 11;
NSLog(@"stu1:%@", stu1);
NSLog(@"stu2:%@", stu2);
}
结果如下:
2015-03-03 22:21:23.948 copy-mutableCopy[8787:301145] stu1:[name=good1, age=10]
2015-03-03 22:21:23.949 copy-mutableCopy[8787:301145] stu2:[name=good2, age=11]
Program ended with exit code: 0