iOS的copy概念详解

1. copy概念

浅复制与深复制
copy即复制,有浅复制和深复制两种。浅复制即引用复制,只拷贝对象的引用,不分配新的内存空间,深复制即对象拷贝,会创建一个对象的副本,分配新的内存空间,与原对象独立。
深复制(深拷贝,内容拷贝,deep copy)
源对象和副本对象是不同的两个对象
源对象引用计数器不变, 副本对象计数器为1(因为是新产生的)
本质是:产生了新的对象

浅复制(浅拷贝,指针拷贝,shallow copy)
源对象和副本对象是同一个对象
源对象(副本对象)引用计数器 + 1, 相当于做一次retain操作
本质是:没有产生新的对象
只有源对象和副本对象都不可变时,才是浅复制,其它都是深复制

NSstring类的retainCount方法,在OS中和iOS中貌似是不同的,(实践)
copy是浅复制,只是复制引用。mutablecopy是深复制,产生了新的空间。
实践结论:
单独对于字符串来说,NSString进行copy时浅复制,新对象地址与原对象一样(想想也可以理解,因为是不可变的常量字符串,存在常量区,因此没有必要额外分配内存)。NSMutableString进行copy后,新对象地址和原对象地址不一样,因此可得出结论NSMutableString进行copy后是深复制,但是深复制后的内容是却是不可变的。
而NSString进行mutablecopy后是深复制,新对象与原对象地址不一样,原对象在常量区,mutablecopy出来的新对象在堆区。NSMutableString进行mutablecopy则是深复制,内容可变。

如何使用copy功能
一个对象可以调用copy或mutableCopy方法来创建一个副本对象
copy : 创建的是不可变副本(如NSString、NSArray、NSDictionary)
mutableCopy :创建的是可变副本(如NSMutableString、NSMutableArray、NSMutableDictionary)

使用copy功能的前提
copy : 需要遵守NSCopying协议,实现copyWithZone:方法
@protocol NSCopying
- (id)copyWithZone:(NSZone *)zone;
@end
mutableCopy : 需要遵守NSMutableCopying协议,实现mutableCopyWithZone:方法
@protocol NSMutableCopying
- (id)mutableCopyWithZone:(NSZone *)zone;
@end

2. @property中的copy关键字

@property内存管理策略的选择
1.非ARC
1> copy : 只用于NSString\block
2> retain : 除NSString\block以外的OC对象
3> assign : 基本数据类型、枚举、结构体(非OC对象),当2个对象相互引用,一端用retain,一端用assign

2.ARC
1> copy : 只用于NSString\block
2> strong : 除NSString\block以外的OC对象
3> weak : 当2个对象相互引用,一端用strong,一端用weak
4> assgin : 基本数据类型、枚举、结构体(非OC对象)

示例代码:
Dog.h

@interface Dog : NSObject<NSCopying>
@property (nonatomic,copy) NSString *name;
@end

Dog.m

@implementation Dog

- (id)copyWithZone:(NSZone *)zone{
    NSLog(@"Dog copying...");
    Dog *d = [[Dog alloc]init];
    d.name = _name;

    return d;
}

- (void)dealloc{
//    [_name dealloc];
    NSLog(@"Dog dealloc...");
//    [super dealloc];
}
@end

main.m

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...

        Dog *d = [Dog new];
        NSMutableString *name = [NSMutableString stringWithFormat:@"金毛"];
        d.name = name;
//        [name appendString:@"哈士奇"];
//        NSLog(@"d.name = %@",d.name);
//        NSLog(@"name:%p  d.name:%p",name,d.name);
        Dog *d2 = [d copy];

        NSLog(@"d=%p  d2=%p",d,d2);
        NSLog(@"d=%@  d2=%@",d.name,d2.name);
//        NSLog(@"d.retaincount = %lu  d2.retainCount = %lu",d.retainCount,d2.retainCount);
//        [d release];
//        NSLog(@"%@   %lu",d2.name,d2.retainCount);

    }
    return 0;
}

知识点一
@property 中的retain,strong,weak,与copy的对比。
MRC模式下:
1.name属性为retain时
Dog.h 里面 @property (nonatomic,retain) NSString *name; name属性为retain时,
Dog *d = [Dog new];
NSString *name = @”hasky”;
d.name = name;
由于是retain,因此d.name = name 时进行的时浅复制,只是复制了引用,当name值变化后,d.name也会跟着变化。
2.name属性为copy时
Dog.h 里面 @property (nonatomic,copy) NSString *name; name属性为copy时,
Dog *d = [Dog new];
NSString *name = @”hasky”;
d.name = name;
由于是copy,因此d.name = name 时进行的是深复制,分配了新的内存空间,d.name与name完全独立。

ARC模式下:
1. name属性为strong,weak时
Dog.h 里面 @property (nonatomic,strong) NSString *name; name属性为strong或weak时,
Dog *d = [Dog new];
NSString *name = @”hasky”;
d.name = name;
由于是strong属性,因此d.name = name 时进行的是浅复制(复制引用),没有分配内存空间,d.name与name地址相同,name改变后d.name也会随之改变。

2.name属性为copy时
Dog.h 里面 @property (nonatomic,copy) NSString *name; name属性为copy时,
Dog *d = [Dog new];
NSString *name = @”hasky”;
d.name = name;
由于是copy属性,因此d.name = name 时进行的是深复制,分配新的内存空间,d.name与name地址不相同,name与d.name互相独立。

3. 自定义类实现copy

自定义对象的copy都是深复制。
1. 遵循协议,实现- (id)copyWithZone:(NSZone *)zone方法。
在该方法中应该分配新的空间,并将原对象的值赋值给新对象,并返回新的对象。
如果没有分配新的空间,则copy后的新对象与原对象地址一样,确认是浅复制(在MRC模式下),奇怪的时新旧对象的retainCount并没有加1(为了保持深复制的特征?)

而原对象release后,新对象依旧可以使用原对象的空间。
    Dog *d = [Dog new];
    Dog *d2 = [d copy];
    NSLog(@"d=%p  d2=%p",d,d2);
    NSLog(@"%lu  %lu",d.retainCount,d2.retainCount);
    [d release];
    NSLog(@"%@   %lu",d2.name,d2.retainCount);
在- (id)copyWithZone:(NSZone *)zone方法中实现了分配空间,并赋值后,则完全就是深拷贝了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值