iOS 拷贝问题

2017-11-08  本文已影响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];
上一篇下一篇

猜你喜欢

热点阅读