【OC】对象复制


前言

NSObject类提供了copy和mutableCopy方法,通过这两个方法即可复制已有对象的副本

一、copy与mutableCopy方法

mutable:可变的
copy方法用于复制对象的副本。通常来说,copy总是返回对象的不可修改的副本,即使该对象本身是可修改的。例如我们调用NSMutableString(可修改的字符串)的copy方法,也将会返回不可修改的字符串对象。
mutableCopy方法用于复制对象的可变副本。通常来说,mutableCopy方法总是返回该对象可修改的副本,即使被复制的对象本身是不可修改的,调用mutableCopy方法复制出来的副本也是可修改的。
例如我们调用NSString的mutableCopy方法,将会返回一个NSMutableString对象。
无论如何,copy和mutableCopy返回的总是原对象的副本,当程序对赋值的副本进行修改时,愿对象不会受影响
在这里插入图片描述
这里我们一定要注意NSRange的定义,这里给出他的源码:
在这里插入图片描述
输出结果:
在这里插入图片描述
上面的程序可以看到即使我们的原对象是不可变的,只要我们复制的副本是可变的,我们得到的副本一定也是可变的,副本的可不可变和他的复制方式有关,而与他的复制对象无关

二、NSCopying与NSMutableCopy协议

我们刚刚在OC自己定义的类中调用了copy与mutablecopy方法,这两个方法用来复制对象的副本确实简便,那么我们自定义的类能否调用copy与mutablecopy呢?
答案是不行的,这里笔者就不赘述了,贴出书上的代码即可。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
当我们调用对象的copy方法来来复制自身时,我们的程序底层实际上是调用copyWithXxxx:方法来完成实际的复制工作。copy返回的实际上就是copyWithXxxx:方法的返回值。mutableCopyWithZone也相同。
但是一定要记得我们重写的方法的方法签名一定要是copyWithZone,这是固定格式

接下来我们给出代码:
协议的接口部分:
在这里插入图片描述
自定义的类的接口部分:
在这里插入图片描述
实现部分:
在这里插入图片描述
主函数部分:
在这里插入图片描述
输出结果:
在这里插入图片描述
这里我们可以看到我们的程序复制a的副本,并将复制的副本赋给b变量,接下来对b重新赋值。
我们看到虽然我们调用的是copy方法,但是我们复制的字符串还是可以修改。而且看出当程序修改b时a并未受影响。

在这里插入图片描述
我们这段话的主要意思就是在我们的NSString类中,已经实现了保证NSString不可变的功能,但是我们自定义的类中没有实现,所以我们调用copy方法时也能修改复制的副本。

三、浅复制与深复制

我们看看如下程序:

类的实现部分:
在这里插入图片描述

函数部分:
在这里插入图片描述

在这里插入图片描述

我们修改d2时我们的程序同时对d1对象的成员变量也进行了改变,但是对于int类型的成员变量d1就没有随之改变。
在这里插入图片描述在这里插入图片描述
从上图我们可以看出,虽然我们的程序创建了两个对象,但两个对象中类型为指针变量的成员变量实际上指向的是同一个对象(这个对象的名字叫做旺财)。所以当我们修改我们由复制粘贴得来的两个对象时,两个对象的属性都会随之改变。
由此我们得出浅复制的定义:当一个对象的成员变量是指针变量时,如果该程序只是复制该指针的地址,而不是真正复制指针所指向的对象,那么这种方式被称为浅复制
另外我们需要知道的是,我们图中的name只是一个指针变量该变量中存放的只是字符串的地址,而不是字符串本身。这点需要着重记忆。

那么我们知道了我们的浅复制党对象的成员变量有指针变量时是无法被单独修改的,那么这里就引出了我们的深复制:可以复制对象本身,并且会“递归”地复制每个指针类型的实例变量
实现深复制只需要将我们指针类型的成员变量递归复制即可
在这里插入图片描述
这样我们就成功修改了我们复制的对象的指针变量
在这里插入图片描述
一般来说,深复制的实现难度大很多,尤其是当该对象包含大量的指针类型的实例变量时,如果某些实例变量里再次包含指针类型的成员变量,那么实现深复制会更加复杂。
一般来说我们的foundation框架中的类大部分只实现了浅复制

四、setter方法的复制选项

我们在前面写程序时,其实笔者一直没有搞懂copy在property中调用的意义,但学到这个略懂了一点。
首先copy指示符就是指定当程序调用setter方法复制时,实际上是将传入参数的副本赋给我们实际程序的成员变量
我们在定义接口时用到property,这里就不给出代码,直接看主函数部分:
在这里插入图片描述
可以看到我们对name进行赋值操作是没有错的,==而且确实赋给了一个可变的字符串类型。==但是当我们修改这个成员变量时却出错了
这是因为我们定义name属性时使用了copy指示符,当我们使用点语法赋值时,==实际上是调用了对应的setter方法,我们的程序实际上会使用参数的副本对name实例变量复制。
//这一步实际上就是指
a.name = [NSMutableString stringWithString:@"二狗"];
实际上我们的setName:方法的代码如下:
在这里插入图片描述
因为我们的copy默认复制不可变副本,所以即使程序传入了NSMutableString,但是因为我们使用点语法时得到的是不可变的副本,所以对象的name的实例变量依然是不可变字符串,所以不可修改

猜你喜欢

转载自blog.csdn.net/weixin_72437555/article/details/130412773