【黑马程序员】oc语法浅拷贝与深拷贝

---------- 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]);

    

    // strstring不是相同对象

    // 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

当然可以看到。对象间的copy不像字符串之间的copy这么简单,我们的类必须要遵守copying协议。在NSObject后面接上 <NSCopying>。遵守了协议,自然一定要实现协议的方法。-(id)copyWithZone:(NSZone *)zone   
zone代表一个空间,系统分配一个新的内存空间给新对象,以完成拷贝。


void studentCopy() {

    Student *stu1 = [Student studentWithName:@"stu1"];

    

    Student *stu2 = [stu1 copy];

    stu2.name = @"stu2";

    

    NSLog(@"stu1:%@", stu1);

    NSLog(@"stu2:%@", stu2);

    

    [stu2 release];

}


我们运行得知,stu2的name是stu2,虽然是copy stu1学生对象来的。但随后对stu2的name属性进行修改并不会改变原对象的值。



假定有一天,我们Student类产生了一个子类,例如叫GoodStudent,那么子类之间的copy就必须要实现如下方法:


- (id)copyWithZone:(NSZone *)zone {

    // 一定要调用父类的方法

    GoodStudent *copy = [super copyWithZone:zone];

    

    copy.age = self.age;

    

    return copy;

}


如果不实现,运行直接崩溃。因为系统不知道要copy子类对象当中的哪个属性。
goodStudent的演示:
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





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值