ios – 如何使用copyWithZone复制结构进行深层复制?

ios – 如何使用copyWithZone复制结构进行深层复制?,第1张

概述我有一个代表结构的类. 这个名为Object的类具有以下属性 @property (nonatomic, strong) NSArray *children;@property (nonatomic, assign) NSInteger type;@property (nonatomic, strong) NSString *name;@property (nonatomic, weak) 我有一个代表结构的类.

这个名为Object的类具有以下属性

@property (nonatomic,strong) NSArray *children;@property (nonatomic,assign) NSInteger type;@property (nonatomic,strong) Nsstring *name;@property (nonatomic,weak) ID parent;

children是一组其他对象. parent是对象父级的弱引用.

我正在尝试复制并粘贴此结构的一个分支.如果选择了根对象,则父级显然是nil.如果对象不是根,则它具有父对象.

为了能够这样做,类型Object的对象必须符合NScopying和NSCoding协议.

这是我在该类上实现的这些协议.

-(ID) copyWithZone: (NSZone *) zone{  Object *obj = [[Object allocWithZone:zone] init];  if (obj) {    [obj setChildren:_children];    [obj setType:_type];    [obj setname:_name];    [obj setParent:_parent];   }  return obj;}- (voID)encodeWithCoder:(NSCoder *)coder {  [coder encodeObject:@(self.type) forKey:@"type"];  [coder encodeObject:self.name forKey:@"name"];  NSData *childrenData = [NSKeyedArchiver archivedDataWithRootObject:self.children];  [coder encodeObject:childrenData forKey:@"children"];  [coder encodeConditionalObject:self.parent forKey:@"parent"]; //*}- (ID)initWithCoder:(NSCoder *)coder {  self = [super init];  if (self) {    _type = [[coder decodeObjectForKey:@"type"] integerValue];    _name = [coder decodeObjectForKey:@"name"];    _parent = [coder decodeObjectForKey:@"parent"]; //*    NSData *childrenData = [coder decodeObjectForKey:@"children"];    _children = [NSKeyedUnarchiver unarchiveObjectWithData:childrenData];    _parent = nil;  }  return self;}

您可能已经注意到我没有引用在initWithCoder上检索或存储self.parent:和encodeWithCoder:因此,对象的每个子对象都带有parent = nil.

我根本就不知道如何存储它.正因为如此.假设我有这个Object结构.

ObjectA > ObjectB > ObjectC

当encoderWithCoder:启动其魔术编码ObjectA时,它也将编码,ObjectB和ObjectC,但是当它开始编码ObjectB时,它找到指向ObjectA的父引用,并将再次启动它,创建一个挂起应用程序的循环引用.我试过了.

如何编码/恢复该父引用?

我需要的是存储一个对象,并在恢复时,恢复一个与存储的相同的新副本.我不想恢复存储的相同对象,而是复制.

注意:我已经按照Ken的建议添加了标有// *的行,但是在initWithCoder上_parent是nil:对于应该有父对象的对象

@H_502_44@解决方法 使用[coder encodeConditionalObject:self.parent forKey:@“parent”]对父进行编码.用-decodeObjectForKey解码它:正常.

这样做的原因是,如果父节点由于其他原因而被存档 – 比如它是树中较高对象的子节点 – 则会恢复对父节点的引用.但是,如果父级只被编码为条件对象,则它不会存储在存档中.解码归档后,父级将为零.

您对children数组进行编码的方式既笨拙又会阻止将父进程正确编码为条件对象.由于您要为子项创建单独的存档,因此没有存档可能同时具有Object及其父项(无条件地).因此,解码归档时将不会恢复到父级的链接.你应该做[编码器编码对象:self.children forKey:@“children”]和_children = [编码器decodeObjectForKey:@“children”].

你的-copyWithZone:实现有问题.副本与原始副本具有相同的子级,但子级不认为副本为其父级.同样,副本将原始父级视为其父级,但该父级对象不包括其子级中的副本.这会让你感到悲伤.

一种选择是利用您的NSCoding支持来制作副本.您将对原始文件进行编码,然后对其进行解码以生成副本.像这样:

-(ID) copyWithZone: (NSZone *) zone{  NSData* selfArchive = [NSKeyedArchiver archivedDataWithRootObject:self];  return [NSKeyedUnarchiver unarchiveObjectWithData:selfArchive];}

复制 *** 作将复制整个子树.因此,它会有自己的孩子,这是原始孩子的副本等.它没有父母.

另一种选择是仅复制原始方面,这些方面不是包含树数据结构的一部分(即类型和名称).也就是说,副本最终没有父项,也没有子项,这是合适的,因为它不在树本身,它只是当时正好在树中的事物的副本.

最后,-copyWithZone:在分配新对象时应该使用[self class]而不是Object.这样,如果您编写了Object的子类及其-copyWithZone:在设置子类的属性之前调用super,则Object中的此实现将分配正确类(子类)的实例.例如:

-(ID) copyWithZone: (NSZone *) zone{  Object *obj = [[[self class] allocWithZone:zone] init];  if (obj) {    [obj setType:_type];    [obj setname:_name];   }  return obj;}
总结

以上是内存溢出为你收集整理的ios – 如何使用copyWithZone复制结构进行深层复制?全部内容,希望文章能够帮你解决ios – 如何使用copyWithZone复制结构进行深层复制?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1002918.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-22
下一篇 2022-05-22

发表评论

登录后才能评论

评论列表(0条)

保存