美文网首页我依然爱iOS
iOS中的浅复制与深复制

iOS中的浅复制与深复制

作者: Cloudox_ | 来源:发表于2017-11-27 10:37 被阅读3次

    当谈到对象复制时都绕不开浅复制与深复制的区分,它们是什么意思呢?

    • 浅复制:只复制对象的指针,两个对象指向的还是同一个地址的内容,操作一个时会影响另一个的值。
    • 深复制:复制对象的内容,两个对象指向两个不同地址的内容,操作一个时不会影响另一个的值。

    在OC中,因为采用内存计数的方式管理内存,所以浅复制时会对同一个内容计数加一,深复制则不会。

    在OC中,复制操作有copy和mutableCopy两种方法,那哪种是浅复制哪种是深复制呢?

    非集合对象

    先把对象大致分为两类:非集合对象与集合对象,至于为什么要这么分,待会讲集合对象的时候再说。

    非集合对象就是指NSString、NSNumber等本身就是具体内容的对象。像NSString这种对象,还有一个相关的叫NSMutableString。所以在非集合对象中又可以分为可变对象和不可变对象。

    对他们进行copy与mutableCopy的含义是:

    • 对于不可变非集合对象(如NSString),copy操作是浅复制,只会复制指针,mutableCopy操作是深复制,
    • 对于可变非集合对象(如NSMutableString),copy和mutableCopy都是深复制,都会创建一个新的同样的内容来返回,但是要注意,copy返回的是不可变对象,也就是说即使你对一个NSMutableString做copy操作,返回给另一个NSMutableString,然后去对这个NSMutableString做变化操作,会报错。

    用代码来看如下:

    NSString *string = @"origin";
    NSString *stringCopy = [string copy];// 浅复制
    NSMutableString *stringMCopy = [string mutableCopy];// 深复制
    
    NSMutableString *string = [NSMutableString stringWithString: @"origin"];
    NSString *stringCopy = [string copy];// 深复制
    NSMutableString *mStringCopy = [string copy];// 深复制
    NSMutableString *stringMCopy = [string mutableCopy];// 深复制
    [mStringCopy appendString:@"mm"]; // crash
    

    集合对象

    上面说了非集合对象,那什么是集合对象呢?集合对象就是指NSArray、NSDictionary、NSSet这些包含其他对象的对象。

    为什么要做这个区分呢?因为浅复制、深复制这两个概念其实并不完全,更准确的应该分为三种:浅复制、深复制、完全深复制。

    在OC中,当你对一个集合对象做深复制时,这个深复制只是单层的,集合内的元素对象其实还只是引用,并不是每一层都是深复制,这一情况,苹果定义为单层深复制(one-level-deep copy)。只有对集合内的每一层都去做深复制,才能够称为完全深复制。

    先说说简单的浅复制与深复制,其实与非集合对象差不多:

    • 对于不可变集合对象(如NSArray),copy操作是浅复制,只会复制指针,mutableCopy操作是深复制,
    • 对于可变集合对象(如NSMutableArray),copy和mutableCopy都是深复制,都会创建一个新的同样的内容来返回,但是要注意两点,一是copy返回的还是不可变对象,二就是上面说的,这个深复制只是单层深复制,里面包含的元素还是指针浅复制。

    代码来说就是:

    NSArray *array = @[@[@"a", @"b"], @[@"c", @"d"];
    NSArray *copyArray = [array copy];// 浅复制
    NSMutableArray *mCopyArray = [array mutableCopy];// 单层深复制
    
    NSMutableArray *array = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
    NSArray *copyArray = [array copy];// 单层深复制,返回不可变对象
    NSMutableArray *mCopyArray = [array mutableCopy];// 单层深复制
    

    那如果要做完全深复制该怎么做呢?

    有两种方法:

    • 一种是用如下所示的方法:
    NSDictionary shallowCopyDict = [[NSDictionary alloc] initWithDictionary:someDictionary copyItems:YES];
    

    copyItems设为YES会对集合中的每一个对象尝试做深复制,但是要求集合中的元素对象遵循NSCopying 协议,否则就会报错。但这其实还是对元素这一层的单层深复制,再下去也没有完全深复制。

    NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]];
    

    以上就是OC中浅复制与深复制的各种应用了,要自己测试到底操作是浅复制还是深复制,可以通过看对象的引用计数是否增加:

    NSLog(@"mArray retain count: %d", [mArray retainCount]);// ARC下不可用
    

    或者直接看两个对象的地址是否一致:

    NSLog(@"string自身指针的地址:%x", &str);
    NSLog(@"string指针指向的对象的地址:%p", str);
    

    查看作者首页

    相关文章

      网友评论

        本文标题:iOS中的浅复制与深复制

        本文链接:https://www.haomeiwen.com/subject/qxprbxtx.html