浅拷贝和深拷贝 iOS 的copy 以及 mutablecopy

先来点基础的

深拷贝和浅拷贝

浅拷贝

  • 指针拷贝,源对象和副本指向的是同一个对象
  • 对象的引用计数器+1,其实相当于做了一次retain操作

深拷贝

  • 内容拷贝,源对象和副本指向的是不同的两个对象
  • 源对象引用计数器不变,副本计数器设置为1

如何理解

很多人对于深浅拷贝总有一些误解,比如很多人都认为 iOS 的 copy 是浅拷贝,mutablecopy 是深拷贝,这是大大地错误的。
博主认为比较好的理解方式是
不要把深浅拷贝和任何的具体的实现方法(函数)画上等号
也就是区分开概念和方式,结果和实现。深浅拷贝是概念、是执行后的结果,copy和mutableCopy等方法只是实现拷贝的途径。
比如说,对于 iOS的 copy 方法

  • 如果原对象是一个不可变对象,那么副本指向原地址(返回自己) –>结果是浅拷贝
  • 如果原对象是一个可变对象,那么副本指向不同的地址(生成新对象) –> 结果是深拷贝

再有,
- 我们对一个 NSArray 做mutablecopy,会返回一个 新的地址,也就是新对象 –>这是一个深拷贝
- 我们对一个 NSString 做mutablecopy,会返回一个 新的数组对象,但是数组中的元素指针还是指向原来的地址。– >很显然这仍然是一个 浅拷贝

所以,我们记住深浅拷贝的概念,并区分不同情境下使用不同的 copy 方法产生的结果是深拷贝还是浅拷贝就 OK 了。
在我们需要使用 copy 时,首先判断我们需要深拷贝还是浅拷贝,然后根据情景选择实现的方法,这样就掌握了深浅拷贝。

iOS 的copy和mutableCopy

iOS中关于拷贝有两个方法,copy和mutableCopy。

首先要纠正的一点是:
很多人都认为 iOS 的 copy 是浅拷贝,mutablecopy 是深拷贝,这是错误的。

copy

  • 需要实现NSCoppying协议
  • 不论原对象是否可变,创建的都是不可变副本(如NSString、NSArray、NSDictionary)
  • 如果原对象是一个不可变对象,那么副本指向原地址(返回自己)
  • 如果原对象是一个可变对象,那么副本指向不同的地址(生成新对象)

mutableCopy

  • 需要先实现NSMutableCopying协议
  • 不管原对象是否可变,创建的都是可变副本(如NSMutableString、NSMutableArray、NSMutableDictionary)
  • 不论原对象是否可变,副本都指向不同的地址,也就是都生成了新的对象

自定义对象的 copy

如果是我们定义的对象,那么需要我们自己要实现NSCopying,NSMutableCopying,这样就能调用copy和mutablecopy了
- (id)copyWithZone:(NSZone*)zone

{

PersonObject*copy = [[[selfclass]allocWithZone:zone]init];

copy->name= [namecopy];

copy->imutableStr= [imutableStrcopy];

copy->age=age;

returncopy;

}

- (id)mutableCopyWithZone:(NSZone*)zone

{

PersonObject*copy =[[[selfclass]allocWithZone:zone]init];

copy.name= [self.namemutableCopy];

copy.age=age;

returncopy;

}

容器的拷贝

有时候我们会有数组等容器对象的完全深拷贝,举个栗子:
当前的 tableview 使用数据源 arry1,点击跳转到下级页面时还需要使用 arry1 的数据,但是有可能对其中的元素进行增删改的操作,但是又不能影响arry1的元素,这时候我们就需要对arry1进行深拷贝:新的数组对象以及数组中的元素也都是新的。

但是我们知道 mutablecopy只会返回一个 新的数组对象数组中的元素指针还是指向原来的地址
那应该如何实现容器的深拷贝呢?

查阅官方文档:
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Collections/Articles/Copying.html

官方描述

要获取一个集合的深拷贝,有两种方法

initWithArray:copyItems:

NSArray *deepCopyArray=[[NSArray alloc] initWithArray:someArray copyItems:YES];

只翻译重要部分,其他的建议通读上面地址里的文档

However, copyWithZone: produces a shallow copy. This kind of copy is only capable of producing a one-level-deep copy. If you only need a one-level-deep copy, you can explicitly call for one as in Listing 2。
不管怎样,copyWithZone:是一个浅拷贝。这种拷贝只能产生一个 一级 的拷贝。如果你只需要一个 一级深度 的拷贝,你可以选择该方法。

NSKeyedUnarchiver

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

If you need a true deep copy, such as when you have an array of arrays, you can archive and then unarchive the collection, provided the contents all conform to the NSCoding protocol. An example of this technique is shown in Listing 3.
如果你需要一个真正的深拷贝,比如你有一个元素是数组的数组(二维数组),你可以对集合进行归档然后再反归档,要让内容都遵循NSCoding协议。这种情况下的一个例子就是上面的。

OK,关于深浅拷贝就先介绍到这里,希望对大家在需要copy的情况下能起到一些帮助。
其实 iOS 中的深浅拷贝内容还是不少的,比如属性中的 copy 如何使用等等,后续相关的内容博主会继续更新,欢迎关注。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Objective-C 中,深拷贝(Deep Copy)和浅拷贝(Shallow Copy)是用于复制对象的两种不同方式。 浅拷贝是指创建一个新的对象,该对象与原始对象共享数据的内存地址。换句话说,新对象只是原始对象的一个引用,对新对象的修改也会影响原始对象。在 Objective-C 中,可以使用 `copy` 方法来执行浅拷贝深拷贝是指创建一个新的对象,并且复制原始对象的所有数据。这意味着新对象有自己的内存地址,对新对象的修改不会影响原始对象。在 Objective-C 中,可以使用 `mutableCopy` 方法来执行深拷贝。 需要注意的是,深拷贝只会复制对象本身,而不会递归地复制对象所包含的其他对象。如果需要对对象的所有数据进行递归复制,可以通过实现 NSCopying 协议来自定义深拷贝操作。 下面是一个示例代码,演示了如何执行浅拷贝深拷贝: ```objective-c #import <Foundation/Foundation.h> @interface Person : NSObject <NSCopying> @property (nonatomic, copy) NSString *name; @end @implementation Person - (instancetype)copyWithZone:(NSZone *)zone { Person *copy = [[Person allocWithZone:zone] init]; copy.name = self.name; return copy; } @end int main(int argc, const char * argv[]) { @autoreleasepool { Person *person1 = [[Person alloc] init]; person1.name = @"John"; // 浅拷贝 Person *person2 = [person1 copy]; NSLog(@"person1: %@, person2: %@", person1.name, person2.name); // 输出:person1: John, person2: John // 深拷贝 Person *person3 = [person1 mutableCopy]; person3.name = @"Emily"; NSLog(@"person1: %@, person3: %@", person1.name, person3.name); // 输出:person1: John, person3: Emily } return 0; } ``` 在上面的示例中,使用 `copy` 方法执行了浅拷贝操作,`mutableCopy` 方法执行了深拷贝操作。注意,为了实现深拷贝,我们在 `Person` 类中遵循了 NSCopying 协议,并重写了 `copyWithZone:` 方法来自定义深拷贝操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值