美文网首页
iOS 拷贝问题

iOS 拷贝问题

作者: 白公子是猫奴 | 来源:发表于2017-11-08 13:42 被阅读0次

    iOS 拷贝问题

    之前在孙**同学面试过程中,发现一些自己对深浅拷贝、可变不可变拷贝的理解有问题,后来在网上也发现有很多误导性的文章,于是学习总结了一下。

    在最开始,我们需要清楚一些关于内存分配方式的基础知识。 一般来说分为静态变量存储区全局变量存储区代码区。 前两个大家都懂的。通常将后三个合并称之为静态存储区,存储的是一些全局变量、静态变量、常量、执行代码等。

    在Objective-C中,不可变数组、不可变字典以及一些常量字符串,都是分配在这个区域的。 所以在提到深浅拷贝的时候,用NSArray举例子的,只能说对内存分配方式就不清楚,因为对一个不可变数组进行copy操作,它实际上返回的是一个对象,跟深浅拷贝无关,因为都是按照retain来处理的。这也就是很多所谓教程提到的指针拷贝。

    对一个不可变数组进行copy,返回的实际是自身,对一个不可变数组进行mutableCopy,会产生一个新的可变数组。

    下面先说一下可变拷贝和不可变拷贝,分别遵循NSCopying和NSMutableCopying协议,需要对应实现copyWithZone:方法和mutableCopyWithZone:方法。

    分两种情况来讲,一种是系统容器类,一种是自定义类

    一、系统容器类

    例如NSArray、NSDictionary,它们已经实现了上面两个协议。 对于它们来说,规则很简单,obj2 = [obj1 copy]返回的必然是一个不可变对象,无论obj1是可变对象还是不可变对象。如果obj1是一个不可变对象,那么它们指向同一个对象。 obj2 = [obj1 mutableCopy]返回的必然是一个可变对象,无论obj1是可变对象还是不可变对象。即使obj1也是一个可变对象,它们仍指向不同地址,是两个对象。

    二、自定义类

    因为copyWithZone:和mutableCopyWithZone:完全由自己来实现,所以代码的不同实现方式,决定了返回对象是什么。

    用代码解释一下:

    - (id)copyWithZone:(NSZone *)zone{
    
         Element *newElement = [[[Element alloc] init] autorelease];
    
        // newElement.elements = [self.elements retain]; 
        //浅拷贝,因为只是new了一个Element对象,内部的elements数组,依然是指向同一个数组。
    
        newElement.elements = [self.elements copy]; 
        //深拷贝,不但new了一个Element对象,而且内部的elements数组也拷贝了一份,和下一句的区别在于返回的是一个不可变数组。
        
        // newElement.elements = [self.elements mutableCopy]; 
        //深拷贝,不但new了一个Element对象,而且内部的elements数组也拷贝了一份,和上一句的区别在于返回的是一个可变数组。
    
        return newElement;
     }
    

    极端一点的例子,例如你直接在copyWithZone:方法中return self;那么obj2 = [obj1 copy]相当于obj2 = obj1,只是一个assign,没有做任何其它操作。

    重点说一下浅拷贝和深拷贝

    首先说一下他的定义:如果把原始的指针提供给新的副本, 就是在进行浅拷贝,另一种方法是依次复制任何子对象, 并把子对象的副本提供给新的对象, 这类复制称为深拷贝。 但个人认为无论是浅拷贝还是深拷贝,都有一个拷贝在里面,之前在网上看到过说浅拷贝相当于retain、什么所谓指针拷贝的,就不要往脑子里进了。 这里以NSMutableArray为例

     NSMutableArray *element = [NSMutableArray arrayWithObject:@1];
     NSMutableArray *array = [NSMutableArray arrayWithObject:element];
     id mutableCopyArray = [array mutableCopy];
    
    • 这一句代码就是浅拷贝,是拷贝了容器自身,返回了一个新的可变数组,指向不同的内存地址。 内部的元素依然是公用的,也就是说,mutableCopyArray[0]也指向element,[mutableCopyArray[0] addObject:***]会影响到array的结果。

       id deepMutableCopyArray = [array test_deepMutableCopy];
      
    • 这一句代码对应的实现是深拷贝,首先它也拷贝了容器自身,返回了一个新的可变数组,指向不同的内存地址。 其次,对内部的元素也进行了拷贝动作,也就是说deepMutableCopyArray[0]是一个新的可变数组,和原来的element是两个数组,修改 [deepMutableCopyArray[0] addObject:***]并不会影响到array的结果。

    相关文章

      网友评论

          本文标题:iOS 拷贝问题

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