zoukankan      html  css  js  c++  java
  • iOS copy&mutableCopy理解

    Copy&mutableCopy
     
    • 通过copy方法可以创建可变或不可变对象的不可变副本,通过mutableCopy可以创建可变或不可变对象的可变副本。
    • 拷贝分为浅拷贝和深拷贝:
      • 浅拷贝:指针拷贝,对一个对象进行浅拷贝,相当于对指向该对象的指针进行复制,产生一个新的指向这个对象的指针。当一个对象销毁后,两个指针都应该置空。
      • 深拷贝:内容拷贝,增加一个指针并且申请一个新的内存,使这个新增的指针指向这个新的内存。使用深拷贝不会出现浅拷贝时重复释放同一块内存的错误!
     
    Not to say, show the code
     
    一、NSArray
    • 示例:不可变数组copy之后数组的地址没有变,是浅拷贝;mutableCopy之后数组的地址不同,但是里面的对象的地址相同,是深度为1的深拷贝。
      • NSArray *array = @[[NSMutableString stringWithString:@"a"], @"b"];
        NSArray *arrCopy = [array copy];
        NSArray *arrMurableCopy = [array mutableCopy];

        NSLog(@"arr address:                   %p", array);
        NSLog(@"arrCopy address:            %p",arrCopy);
        NSLog(@"arrMurableCopy address:%p", arrMurableCopy);

        NSLog(@"arr first address:                   %p", [array objectAtIndex:0]);
        NSLog(@"arrCopy first address:            %p", [arrCopy objectAtIndex:0]);
        NSLog(@"arrMurableCopy first address:%p", [arrMurableCopy objectAtIndex:0]);

        [self myNslog:array];
        [self myNslog:arrCopy];
        [self myNslog:arrMurableCopy];

        [array[0] appendString:@"aaa"];

        NSLog(@"arr address:                   %p", array);
        NSLog(@"arrCopy address:            %p",arrCopy);
        NSLog(@"arrMurableCopy address:%p", arrMurableCopy);

        NSLog(@"arr first address:                  %p", [array objectAtIndex:0]);
        NSLog(@"arrCopy first address:           %p", [arrCopy objectAtIndex:0]);
        NSLog(@"arrMurableCopy first address:%p", [arrMurableCopy objectAtIndex:0]);

        [self myNslog:array];
        [self myNslog:arrCopy];
        [self myNslog:arrMurableCopy];
            
      • arr address:                              0x146e5a9f0
        arrCopy address:                      0x146e5a9f0
        arrMurableCopy address:         0x146e3aa90
        arr first address:                       0x146e5a9b0
        arrCopy first address:               0x146e5a9b0
        arrMurableCopy first address:  0x146e5a9b0
        (
            a,
            b
        )
        (
            a,
            b
        )
        (
            a,
            b
        )
        arr address:                             0x146e5a9f0
        arrCopy address:                     0x146e5a9f0
        arrMurableCopy address:        0x146e3aa90
        arr first address:                      0x146e5a9b0
        arrCopy first address:              0x146e5a9b0
        arrMurableCopy first address: 0x146e5a9b0
        (
            aaaa,
            b
        )
        (
            aaaa,
            b
        )
        (
            aaaa,
            b
        )
    • 不可变数组copy之后数组的地址没有变,是浅拷贝;mutableCopy之后数组的地址不同,但是里面的对象的地址相同,是深度为1的深拷贝。
    • 从打印结果可以看出,打印的数组的第一个对象的地址相同,可见里面存放的是对象的内存地址, 并没有开辟内存空间存放对象。所以当为一个数组的第一个对象附加aaa后,所有数组的第一个对象值都变为aaaa
     
    、NSMutableArray
    • 示例一:从结果可见,可变数组copy 和 mutableCopy之后数组的地址都不同,然而数组的第一个对象的地址都相同,说明没有开辟新的地址存放数组里面的对象,说明进行了深度为1的深拷贝,数组里面存的是 a , b 对象组成的数组的首地址。改变一个数组的第一个值,其他数组也发生变化。
      • // 可变数组
        NSMutableArray *mutableArr = [NSMutableArray arrayWithArray:@[[NSMutableString stringWithString:@"a"], @"b"]];
        NSMutableArray *mutableArrCopy = [mutableArr copy];
        NSMutableArray *mutableArrMutableCopy = [mutableArr mutableCopy];

        NSLog(@"mutableArr address:                   %p", mutableArr);
        NSLog(@"mutableArrCopy address:            %p", mutableArrCopy);
        NSLog(@"mutableArrMutableCopy address:%p", mutableArrMutableCopy);

        NSLog(@"mutableArr first address:                  %p", [mutableArr objectAtIndex:0]);
        NSLog(@"mutableArrCopy first address:           %p", [mutableArrCopy objectAtIndex:0]);
        NSLog(@"mutableArrMutableCopy first address:%p", [mutableArrMutableCopy objectAtIndex:0]);

        [self myNslog:mutableArr];
        [self myNslog:mutableArrCopy];
        [self myNslog:mutableArrMutableCopy];


        // 可变数组改变第一个值
        [mutableArr[0] appendString:@"aaa"];

        NSLog(@"mutableArr first address:                   %p", [mutableArr objectAtIndex:0]);
        NSLog(@"mutableArrCopy first address:            %p", [mutableArrCopy objectAtIndex:0]);
        NSLog(@"mutableArrMutableCopy first address:%p", [mutableArrMutableCopy objectAtIndex:0]);

        [self myNslog:mutableArr];
        [self myNslog:mutableArrCopy];
        [self myNslog:mutableArrMutableCopy];
      • mutableArr address:                            0x135e2e040
        mutableArrCopy address:                    0x135e19880
        mutableArrMutableCopy address:       0x135d0f0a0
        mutableArr first address:                     0x135d49580
        mutableArrCopy first address:             0x135d49580
        mutableArrMutableCopy first address:0x135d49580
        (
            a,
            b
        )
        (
            a,
            b
        )
        (
            a,
            b
        )
        mutableArr first address:                     0x135d49580
        mutableArrCopy first address:             0x135d49580
        mutableArrMutableCopy first address:0x135d49580
        (
            aaaa,
            b
        )
        (
            aaaa,
            b
        )
        (
            aaaa,
            b
        )
    • 从结果可见,可变数组copy 和 mutableCopy之后数组的地址都不同,然而数组的第一个对象的地址都相同,说明没有开辟新的地址存放数组里面的对象,说明进行了深度为1的深拷贝,数组里面存的是 a , b 对象组成的数组的首地址。改变一个数组的第一个值,其他数组也发生变化。
     
    • 示例二:这里创建一个新的可变字符串对象,并赋值给 mutableArr[0],而其他数组指针指向的对象不变,所以输出时其他数组值不变。
      • // 设置新值
        mutableArr[0] = [NSMutableString stringWithString:@"A"];

        NSLog(@"mutableArr first address:%p", [mutableArr objectAtIndex:0]);
        NSLog(@"mutableArrCopy first address:%p", [mutableArrCopy objectAtIndex:0]);
        NSLog(@"mutableArrMutableCopy first address:%p", [mutableArrMutableCopy objectAtIndex:0]);

        [self myNslog:mutableArr];
        [self myNslog:mutableArrCopy];
        [self myNslog:mutableArrMutableCopy];
      • 设置新值之后的打印;
      • mutableArr first address:                     0x12f625590
        mutableArrCopy first address:             0x135d49580
        mutableArrMutableCopy first address:0x135d49580
        (
            A,
            b
        )
        (
            A,
            b
        )
        (
            A,
            b
        )
    • 这里创建一个新的可变字符串对象,并赋值给 mutableArr[0],而其他数组指针指向的对象不变,所以输出时其他数组值不变。
     
    • 示例三:这里创建了一个新的可变字符串对象,并将其内存地址保存到指针mutableArr[3]中。而其他几个数组指针的引用不受影响。
      • // 添加新值
        [mutableArr addObject:[NSMutableString stringWithString:@"c"]];

        NSLog(@"mutableArr first address:                   %p", [mutableArr objectAtIndex:0]);
        NSLog(@"mutableArrCopy first address:            %p", [mutableArrCopy objectAtIndex:0]);
        NSLog(@"mutableArrMutableCopy first address:%p", [mutableArrMutableCopy objectAtIndex:0]);

        [self myNslog:mutableArr];
        [self myNslog:mutableArrCopy];
        [self myNslog:mutableArrMutableCopy];
      • mutableArr first address:                     0x135d49580
        mutableArrCopy first address:             0x135d49580
        mutableArrMutableCopy first address:0x135d49580
        (
         
          a,
            b,
            c
        )

        (
            a,
            b
        )
        (
            a,
            b
        )
    • 这里创建了一个新的可变字符串对象,并将其内存地址保存到指针mutableArr[3]中。而其他几个数组指针的引用不受影响
     
    • 示例四:操作的是mutableArr对对象的引用,所以不会影响到其他数组
      • // 操作数组的引用
        NSMutableString *mutableString = [NSMutableString stringWithString:mutableArr[0]];
        [mutableString appendString:@"aaa"];
        [mutableArr replaceObjectAtIndex:0 withObject:mutableString];

        NSLog(@"mutableArr first address:                  %p", [mutableArr objectAtIndex:0]);
        NSLog(@"mutableArrCopy first address:           %p", [mutableArrCopy objectAtIndex:0]);
        NSLog(@"mutableArrMutableCopy first address:%p", [mutableArrMutableCopy objectAtIndex:0]);

        [self myNslog:mutableArr];
        [self myNslog:mutableArrCopy];
        [self myNslog:mutableArrMutableCopy];
      • mutableArr first address:                     0x135d49570
        mutableArrCopy first address:             0x135d49580
        mutableArrMutableCopy first address:0x135d49580
        (
         
          aaaa,
            b,
            c
        )

        (
            a,
            b
        )
        (
            a,
            b
        )
      • // 操作数组的引用
        [mutableArr removeObjectAtIndex:1];

        NSLog(@"mutableArr first address:                   %p", [mutableArr objectAtIndex:0]);
        NSLog(@"mutableArrCopy first address:            %p", [mutableArrCopy objectAtIndex:0]);
        NSLog(@"mutableArrMutableCopy first address:%p", [mutableArrMutableCopy objectAtIndex:0]);

        [self myNslog:mutableArr];
        [self myNslog:mutableArrCopy];
        [self myNslog:mutableArrMutableCopy];
      • mutableArr first address:                     0x135d49580
        mutableArrCopy first address:             0x135d49580
        mutableArrMutableCopy first address:0x135d49580
        (
         
          a
        )

        (
            a,
            b
        )
        (
            a,
            b
        )
    • 操作的是mutableArr对对象的引用,所以不会影响到其他数组
     
    三、NSString
    • 示例:copy 之后地址没有变,mutableCopy之后地址发生了变化,当改变了stringMutableCopy字符串之后,其他连个字符串没有发生变化,说明NSString copy 是浅拷贝,mutableCopy是深拷贝
      • NSString *string = @"abc";
        NSString *stringCopy = [string copy];
        NSMutableString *stringMutableCopy = [string mutableCopy];

        NSLog(@"string                   = %p", string);
        NSLog(@"stringCopy            = %p", stringCopy);
        NSLog(@"stringMutableCopy = %p", stringMutableCopy);

        [stringMutableCopy appendString:@"def"];

        NSLog(@"string                   = %p", string);
        NSLog(@"stringCopy            = %p", stringCopy);
        NSLog(@"stringMutableCopy = %p", stringMutableCopy);

        NSLog(@"string                   = %@", string);
        NSLog(@"stringCopy            = %@", stringCopy);
        NSLog(@"stringMutableCopy = %@", stringMutableCopy);
      • string                      = 0x1000f0310
        stringCopy              = 0x1000f0310
        stringMutableCopy = 0x14752fcf0
        string                      = 0x1000f0310
        stringCopy              = 0x1000f0310
        stringMutableCopy = 0x14752fcf0
        string                      = abc
        stringCopy              = abc
        stringMutableCopy = abcdef
    • copy 之后地址没有变,mutableCopy之后地址发生了变化,当改变了stringMutableCopy字符串之后,其他连个字符串没有发生变化,说明NSString copy 是浅拷贝,mutableCopy是深拷贝
     
    四、NSMutableString
    • 示例:
      • NSMutableString *mutaleString = [NSMutableString stringWithString:@"a"];
        NSMutableString *mutaleStringcopy = [mutaleString copy];
        NSMutableString *mutaleStringmutableCopy = [mutaleString mutableCopy];

        NSLog(@"mutaleString                    = %p", mutaleString);
        NSLog(@"mutaleStringcopy             = %p", mutaleStringcopy);
        NSLog(@"mutaleStringmutableCopy = %p", mutaleStringmutableCopy);

        [mutaleString appendString:@"bcd"];

        NSLog(@"mutaleString                   = %p", mutaleString);
        NSLog(@"mutaleStringcopy             = %p", mutaleStringcopy);
        NSLog(@"mutaleStringmutableCopy = %p", mutaleStringmutableCopy);

        NSLog(@"mutaleString                    = %@", mutaleString);
        NSLog(@"mutaleStringcopy             = %@", mutaleStringcopy);
        NSLog(@"mutaleStringmutableCopy = %@", mutaleStringmutableCopy);
      • mutaleString                       = 0x14e637470
        mutaleStringcopy               = 0xa000000000000611
        mutaleStringmutableCopy = 0x14e6374b0
        mutaleString                       = 0x14e637470
        mutaleStringcopy               = 0xa000000000000611
        mutaleStringmutableCopy = 0x14e6374b0
        mutaleString                      = abcd
        mutaleStringcopy              = a
        mutaleStringmutableCopy = a
      • mutaleString = [NSMutableStringstringWithString:@"A"];

        NSLog(@"mutaleString                    = %p", mutaleString);
        NSLog(@"mutaleStringcopy             = %p", mutaleStringcopy);
        NSLog(@"mutaleStringmutableCopy = %p", mutaleStringmutableCopy);

        NSLog(@"mutaleString                    = %@", mutaleString);
        NSLog(@"mutaleStringcopy             = %@", mutaleStringcopy);
        NSLog(@"mutaleStringmutableCopy = %@", mutaleStringmutableCopy);
      • mutaleString                       = 0x14e637470
        mutaleStringcopy               = 0xa000000000000611
        mutaleStringmutableCopy = 0x14e6374b0
        mutaleString                       = 
        0x13c657000
        mutaleStringcopy               = 0xa000000000000611
        mutaleStringmutableCopy = 0x14e6374b0
        mutaleString                       = A
        mutaleStringcopy               = a
        mutaleStringmutableCopy = a
      • copy 和 mutableCopy都进行了深拷贝,开辟了 新的地址空间存储 拷贝后的变量;
      • 注意:copy 后的地址 0xa000000000000611 跟其他的不一样,copy后的对象是不可变的,强行修改会导致程序崩溃。
      • -[NSTaggedPointerString appendString:]: unrecognized selector sent to instance 0xa000000000000611
        *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSTaggedPointerString appendString:]: unrecognized selector sent to instance 0xa000000000000611'
     
    五、NSMutableDictionary
    • 示例一:mutableDict 的索引key1, key2, key3 分别对应对象 mutableStr1, mutableStr2, mutableStr3 的内存地址,copy 后所有的字典第一个对象的地址都相同,对字典拷贝也是浅拷贝。
      • NSMutableString *mutableStr1 = [NSMutableString stringWithString:@"a"];
        NSMutableString *mutableStr2 = [NSMutableString stringWithString:@"b"];
        NSMutableString *mutableStr3 = [NSMutableString stringWithString:@"c"];
        NSMutableDictionary *mutableDict = [NSMutableDictionary dictionaryWithObjects:@[mutableStr1, mutableStr2, mutableStr3] forKeys:@[@"key1", @"key2", @"key3"]];
        NSMutableDictionary *mutableDictCopy = [mutableDict copy];
        NSMutableDictionary *mutableDictMutableCopy = [mutableDict mutableCopy];

        NSLog(@"mutableDict                   = %p", mutableDict);
        NSLog(@"mutableDictCopy            = %p", mutableDictCopy);
        NSLog(@"mutableDictMutableCopy = %p", mutableDictMutableCopy);


        NSLog(@"mutableDict first address                    = %p", mutableDict[@"key1"]);
        NSLog(@"mutableDictCopy first address             = %p", mutableDictCopy[@"key1"]);
        NSLog(@"mutableDictMutableCopy first address  = %p", mutableDictMutableCopy[@"key1"]);

        [mutableDict[@"key1"] appendString:@"aaa"];

        NSLog(@"mutableDict                    = %@", mutableDict);
        NSLog(@"mutableDictCopy             = %@", mutableDictCopy);
        NSLog(@"mutableDictMutableCopy = %@", mutableDictMutableCopy);

        NSLog(@"mutableDict first address                    = %p", mutableDict[@"key1"]);
        NSLog(@"mutableDictCopy first address             = %p", mutableDictCopy[@"key1"]);
        NSLog(@"mutableDictMutableCopy first address  = %p", mutableDictMutableCopy[@"key1"]);
      • mutableDict                                            = 0x15f62f7d0
        mutableDictCopy                                    = 0x15f62f800
        mutableDictMutableCopy                       = 0x15f62f570
        mutableDict first address                       = 0x15f62f530
        mutableDictCopy first address               = 0x15f62f530
        mutableDictMutableCopy first address  = 0x15f62f530
        mutableDict            = {
            key1 = aaaa;
            key2 = b;
            key3 = c;
        }
        mutableDictCopy        = {
            key1 = aaaa;
            key2 = b;
            key3 = c;
        }
        mutableDictMutableCopy = {
            key1 = aaaa;
            key2 = b;
            key3 = c;
        }
        mutableDict first address                       = 0x15f62f530
        mutableDictCopy first address               = 0x15f62f530
        mutableDictMutableCopy first address  = 0x15f62f530
    • mutableDict 的索引key1, key2, key3 分别对应对象 mutableStr1, mutableStr2, mutableStr3 的内存地址,copy 后所有的字典第一个对象的地址都相同,对字典拷贝也是浅拷贝。
    • 对key1对应的对象mutableStr1进行修改后,由于指向同一个字典,所以输出相同,第一个对象的地址也相同。
     
    • 示例二:
      • [mutableDict setObject:@"A" forKey:@"key1"];

        NSLog(@"mutableDict                   = %@", mutableDict);
        NSLog(@"mutableDictCopy            = %@", mutableDictCopy);
        NSLog(@"mutableDictMutableCopy = %@", mutableDictMutableCopy);

        NSLog(@"mutableDict first address                    = %p", mutableDict[@"key1"]);
        NSLog(@"mutableDictCopy first address             = %p", mutableDictCopy[@"key1"]);
        NSLog(@"mutableDictMutableCopy first address  = %p", mutableDictMutableCopy[@"key1"]);
      • mutableDict            = {
            key1 = A;
            key2 = b;
            key3 = c;
        }
        mutableDictCopy        = {
            key1 = a;
            key2 = b;
            key3 = c;
        }
        mutableDictMutableCopy = {
            key1 = a;
            key2 = b;
            key3 = c;
        }
        mutableDict first address                       =
        0x1000fc390
        mutableDictCopy first address               = 0x15f62f530
        mutableDictMutableCopy first address  = 0x15f62f530
     
    • mutableDict中key1存放的是第一个对象的内存地址,[mutableDict setObject:@"A" forKey:@"key1”]; 将key1中的内存地址修改为 @"A"的内存地址,不会影响到其他引用所指向的对象。
     
    • 示例三:为 mutableDict 添加先得键值对,没有影响到其他字典指针,所以只有mutableDict发生变化。
      • [mutableDict setObject:@"d" forKey:@"key4"];

        NSLog(@"mutableDict                   = %@", mutableDict);
        NSLog(@"mutableDictCopy            = %@", mutableDictCopy);
        NSLog(@"mutableDictMutableCopy = %@", mutableDictMutableCopy);

        NSLog(@"mutableDict first address                    = %p", mutableDict[@"key1"]);
        NSLog(@"mutableDictCopy first address             = %p", mutableDictCopy[@"key1"]);
        NSLog(@"mutableDictMutableCopy first address  = %p", mutableDictMutableCopy[@"key1"]);
      • mutableDict            = {
            key1 = A;
            key2 = b;
            key3 = c;
            key4 = d;

        }
        mutableDictCopy        = {
            key1 = a;
            key2 = b;
            key3 = c;
        }
        mutableDictMutableCopy = {
            key1 = a;
            key2 = b;
            key3 = c;
        }
        mutableDict first address                       = 
        0x15f62f530
        mutableDictCopy first address               = 0x15f62f530
        mutableDictMutableCopy first address  = 0x15f62f530
    • 为 mutableDict 添加先得键值对,没有影响到其他字典指针,所以只有mutableDict发生变化。
     
    总结:NSMutableArray和NSMutableDictionary的复制是浅复制,NSMutableString的复制是深复制。由于数组或字典中对象数目或大小可能非常大,所以对对象的复制可能引起大量开销,因此这里只复制引用可以节省开销。
      
  • 相关阅读:
    序列化和反序列化
    抽象类与接口
    为了忘却的纪念
    gmail和hotmail也有企业邮局
    tag's tag
    在互联网上裸奔
    音乐网站,可以自己弹琴,歌谱整理
    今天看了ning的介绍,很有意思
    昨天服务器出现问题,解决过程如下所述
    google Trends
  • 原文地址:https://www.cnblogs.com/10-19-92/p/5607807.html
Copyright © 2011-2022 走看看