[解析]Objective-C 深浅拷贝

在C++中,深浅拷贝的区别如下:

  • 浅拷贝。

缺省拷贝构造函数在拷贝过程中是按字节复制的,对于指针型成员变量只复制指针本身,而不复制指针所指向的目标,也就是两个对象中成员指针变量指向同一块内存

  • 深拷贝。对一个对象进行深拷贝,系统会为新对象变量中得每一个对象成员分配空间,并将原对象成员内容赋值给新对象对应的成员变量。

在iOS中,由于Objective-C自身提供了copy函数,但是深浅难辨,因此做下总结:

  • 非容器变量(immutable对象与mutable对象的区分)
    如下代码所示,可以得出结论,对于一个immutable对象,进行copy得到的对象是浅拷贝,进行mutableCopy得到的对象是深拷贝
    NSString *string = @"animal";
    NSString *stringCopy11 = [string copy];
    NSMutableString *stringMutableCopy11 = [string mutableCopy];
    NSString *stringCopy12 = [string mutableCopy];//非法,容易错误操作
    NSMutableString *stringMutableCopy12 = [string copy];//非法,容易错误操作

    NSLog(@"%p \n%p \n%p \n%p \n%p", string, stringCopy11, stringCopy12, stringMutableCopy11, stringMutableCopy12);

    //output
    /*
    2015-09-30 21:38:50.665 HelloWorld[966:49309] 
    0x10a0560a8 
    0x10a0560a8 
    0x7fd2f049eb00 
    0x7fd2f049ce90 
    0x10a0560a8
    */

如下代码所示,可以得出结论,对于一个mutable对象,不管进行copy或mutableCopy得到的对象都是深拷贝

    NSMutableString *mutableString1 = [[NSMutableString alloc] initWithString:@"animal"];
    NSString *stringCopy21 = [mutableString1 copy];
    NSMutableString *stringMutableCopy21 = [mutableString1 mutableCopy];
    NSMutableString *stringCopy22 = [mutableString1 copy];//非法,容易错误操作
    NSString *stringMutableCopy22 = [mutableString1 mutableCopy];//非法,容易错误操作
    NSLog(@"%p \n%p \n%p \n%p \n%p", mutableString1, stringCopy21, stringCopy22, stringMutableCopy21, stringMutableCopy22);

    //output
    /*
    2015-09-30 21:38:50.665 HelloWorld[966:49309] 
    0x7fd2f049d8c0 
    0x7fd2f049d920 
    0x7fd2f049e430 
    0x7fd2f049d940 
    0x7fd2f049e450
    */
  • 容器变量
    • 由以下实验可以看出,容器变量与非容器变量在进行copy与mutableCopy时的情况是一致的,关键在于容器变量如array中得对象都是浅拷贝,其都指向对应的同一块内存
    • trueDeepCopy31、trueDeepCopy33并不是真正意义上的深拷贝,其效果还是同前面讨论的一样并不是真正意义上得深拷贝,而trueDeepCopy32才算的上时真正意义上的深拷贝,因为其对象地址、对象成员地址都都与原来的对象不同。
    NSArray *a1 = @[@"dog", @"cat"];
    NSArray *a2 = @[@"tiger", @"lion"];
    NSArray *a3 = @[@"cow", @"sheep"];
    NSArray *array = @[a1, a2, a3];
    NSArray *arrayCopy11 = [array copy];
    NSArray *arrayCopy12 = [array mutableCopy];
    NSMutableArray *arrayMutableCopy11 = [array mutableCopy];
    NSMutableArray *arrayMutableCopy12 = [array copy];

    NSLog(@"%p %p %p \n%p %p %p\n%p %p %p\n%p %p %p\n%p %p %p", array, array[0], array[0][0],
          arrayCopy11, arrayCopy11[0], arrayCopy11[0][0],
          arrayCopy12, arrayCopy12[0], arrayCopy12[0][0],
          arrayMutableCopy11, arrayMutableCopy11[0], arrayMutableCopy11[0][0],
          arrayMutableCopy12, arrayMutableCopy12[0], arrayMutableCopy12[0][0]);

//output
    /*
    2015-09-30 22:09:07.284 HelloWorld[1284:60191] 
    0x7fa2ab52fd80 0x7fa2ab52ffb0 0x10b0bc0b8 
    0x7fa2ab52fd80 0x7fa2ab52ffb0 0x10b0bc0b8
    0x7fa2ab52fc20 0x7fa2ab52ffb0 0x10b0bc0b8
    0x7fa2ab52f010 0x7fa2ab52ffb0 0x10b0bc0b8
    0x7fa2ab52fd80 0x7fa2ab52ffb0 0x10b0bc0b8
    */

    NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithArray:array];
    NSArray *arrayCopy21 = [array copy];
    NSArray *arrayCopy22 = [array mutableCopy];
    NSMutableArray *arrayMutableCopy21 = [array mutableCopy];
    NSMutableArray *arrayMutableCopy22 = [array copy];

    NSLog(@"%p %p %p \n%p %p %p\n%p %p %p\n%p %p %p\n%p %p %p",
          mutableArray, mutableArray[0], mutableArray[0][0],
          arrayCopy21, arrayCopy21[0], arrayCopy21[0][0],
          arrayCopy22, arrayCopy22[0], arrayCopy22[0][0],
          arrayMutableCopy21, arrayMutableCopy21[0], arrayMutableCopy21[0][0],
          arrayMutableCopy22, arrayMutableCopy22[0], arrayMutableCopy22[0][0]);

    //output
    /*
    2015-09-30 22:09:07.284 HelloWorld[1284:60191] 
    0x7fa2ab52f060 0x7fa2ab52ffb0 0x10b0bc0b8 
    0x7fa2ab52fd80 0x7fa2ab52ffb0 0x10b0bc0b8
    0x7fa2ab52f0b0 0x7fa2ab52ffb0 0x10b0bc0b8
    0x7fa2ab52f100 0x7fa2ab52ffb0 0x10b0bc0b8
    0x7fa2ab52fd80 0x7fa2ab52ffb0 0x10b0bc0b8
    */

    NSArray *trueDeepCopy31 = [[NSArray alloc] initWithArray:array copyItems:YES];
    NSArray *trueDeepCopy32 = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:array]];
    NSMutableArray *trueDeepCopy33 = [[NSMutableArray alloc] initWithArray:array copyItems:YES];

    NSLog(@"%p %p %p \n%p %p %p\n%p %p %p", trueDeepCopy31, trueDeepCopy31[0], trueDeepCopy31[0][0],
          trueDeepCopy32, trueDeepCopy32[0], trueDeepCopy32[0][0],
          trueDeepCopy33, trueDeepCopy33[0], trueDeepCopy33[0][0]);

    //output
    /*
    2015-09-30 23:13:18.877 HelloWorld[637:12672] 
    0x7fe7414a8d90 0x7fe7414a9f00 0x10a5050b8 
    0x7fe7414a96a0 0x7fe7414a9f00 0x10a5050b8
    0x7fe7414a9770 0x7fe7414a9f00 0x10a5050b8
    0x7fe7414aa070 0x7fe7414a9f00 0x10a5050b8
    0x7fe7414a96a0 0x7fe7414a9f00 0x10a5050b8
    2015-09-30 23:13:18.877 HelloWorld[637:12672] 
    0x7fe7414aa0c0 0x7fe7414a9f00 0x10a5050b8 
    0x7fe7414aaed0 0x7fe7414aab80 0x7fe7414aab20
    0x7fe7414aaae0 0x7fe7414a9f00 0x10a5050b8
    */
  • 自定义拷贝
    自定义拷贝需要继承NSCopying、NSMutableCopying协议,重写以下两个方法。
- (id)copyWithZone:(NSZone *)zone;
- (id)mutableCopyWithZone:(NSZone *)zone;
//示例
//FSJAnimal.h
@interface FSJAnimal : NSObject
@property(nonatomic, copy) NSString *name;
@property(nonatomic, strong) NSSet *families;

-(id)initWithName:(NSString *)name;
@end

//FSJAnimal.m
@interface FSJAnimal()<NSCopying, NSMutableCopying> 
@end

@implementation FSJAnimal
@synthesize name;
@synthesize families;
//懒初始化
-(NSSet*)families{
    return [_internalFamilies copy];
} 

-(id)initWithName:(NSString *)name
{
    if(self = [super init])
    {
        _name = name;
        _internalFamilies = [[NSMutableSet alloc] init];
    }
    return self;
}
- (id)copyWithZone:(NSZone *)zone
{
    FSJAnimal *copy = [[[self class] alloc] init];
    copy->name = [name copy];
    copy->families = [families copy];
    return copy;
}

- (id)mutableCopyWithZone:(NSZone *)zone
{
    FSJAnimal *copy = [[[self class] alloc] init];
    copy->name = [name mutableCopy];
    copy->families = [families mutableCopy];
    return copy;
}
@end
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值