介绍两种方法使用NSCopying的协议copyWithZone方法去实现objects的copy。
你有两种方法通过实现NSCopying的协议copyWithZone创建copies:
(1).单纯使用alloc和init
(2).使用 NSCopyObject
对于如何选择,你需要考虑:
(1).我需要深拷贝还是浅拷贝
(2).我需要继承NSCopying的一些方法吗
1.深拷贝还是浅拷贝
拷贝一个object也就是创建一个新的实例,并且初始化为拷贝源的值。对于像boolean,integer这类值,拷贝就是直接赋值。对于指针
形的object就分为浅拷贝和深拷贝。浅拷贝是只创建一个新的指针,并指向同一块数据。深拷贝就是数据和指针都创建。我们来看:
深拷贝:
{
[myVariable autorelease];
myVariable = [newValue copy];
}
浅拷贝:
{
[myVariable autorelease];
myVariable = [newValue retain];
}
浅拷贝2:
{
myVariable = newValue;
}
独立的拷贝
顾名思义,独立的拷贝只能是深拷贝,但通常我们需要把深拷贝和浅拷贝结合获得最佳效果。比如指针这种可以看成数据容器的object,我们需要深拷贝,而像委托这种复杂的object,浅拷贝会比较好,比如:
{
NSString *productName;
float price;
id delegate;
}
@end
通过继承NSCopying,我们现在深拷贝一个Product,这时对应于这个深拷贝的Product的数据区的productName; float price; delegate;
三个object,我们看图:
productName的值不同,是深拷贝,而delegate的值相同,是浅拷贝,price无所谓深浅。
2.使用“alloc, init…”的方法
如果你的类没有从父类继承NSCopying,那么你需要用alloc, init…和setter方法自己去实现copyWithZone,比如上面那个Product的例子,我们可以这样实现:
{
Product *copy = [[[self class] allocWithZone: zone]
initWithProductName:[self productName]
price:[self price]];
[copy setDelegate:[self delegate]];
return copy;
}
3.使用NSCopyObject()
如果你从父类继承了NSCopying,没有像上面那样自己写copyWithZone,你要注意这个父类可能使用了NScopyObject函数去实现 copyWithZone(你是继承过来的,当然也是了)。而NSCopyObject其实是浅拷贝,如NSCell这个类实现的 copyWithZone:
{
NSCell *cellCopy = NSCopyObject(self, 0, zone);
/* Assume that other initialization takes place here. */
cellCopy->image = nil;
[cellCopy setImage:[self image]];
return cellCopy;
}
由于是浅拷贝,那么需要深拷贝的object就要额外对待。比如上面的image,我们在setter方法中需要:
{
[image autorelease];
image = [anImage retain];
}
父类的NSCopyObject函数会拓展子类的实现,现在我们看NSCell的子类NSSlideCell怎么实现:
{
id cellCopy = [super copyWithZone:zone];
/* Assume that other initialization takes place here. */
cellCopy->titleCell = nil;
[cellCopy setTitleCell:[self titleCell]];
return cellCopy;
}
父类的copyWithZone会被调用。
使用NSCopyObject还需要注意retain count,下面这张图很好说明了这点:
我们看到NSCopyObject连retain count都直接复制过来,而copyWithZone则会修正它。
4.拷贝可变和不可变的Objects
NSCopying产生的是不可变的拷贝,不管其拷贝源是否可变。不可变的Object使用NSCopying很高效,NSCopying甚至可以去retain拷贝源,比如:
return [self retain];
}
而当我们要拷贝可变的objects时,则是使用NSMutableCopying,这个协议声明了mutableCopyWithZone方法。 可变的拷贝通常调用NSObject的方法mutableCopy,这个方法调用了 mutableCopyWithZone。
5 可变与不可变
参考:http://www.cnblogs.com/gaoxiao228/archive/2012/04/21/2462561.html
如果对一不可变对象复制,copy是指针复制(浅拷贝)和mutableCopy就是对象复制(深拷贝)。
如果是对可变对象复制,都是深拷贝,但是copy返回的对象是不可变的。
对于容器而言,其元素对象始终是指针复制。如果需要元素对象也是对象复制,就需要实现深拷贝
NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:
[NSKeyedArchiver archivedDataWithRootObject: array]];
trueDeepCopyArray是完全意义上的深拷贝,而deepCopyArray则不是,对于deepCopyArray内的不可变元素其还是指针复制。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)