创建 NSManagedObject 的副本

Posted

技术标签:

【中文标题】创建 NSManagedObject 的副本【英文标题】:Create a copy of a NSManagedObject 【发布时间】:2012-12-10 00:57:25 【问题描述】:

我需要将NSManagedObject 的内容临时存储到字典中。因为核心数据有自己的内存管理程序,我不想保留任何指向NSManagedObject 字段的强指针,此时只有值是感兴趣的(值在视图控制器之间传递,MOC 不同)。我也不能创建弱指针,因为我想控制内存回收何时完成。

我尝试了几件事,都失败了或不符合目的。

    重复的[[myNSMO alloc] initWithEntity:[NSEntityDescription entityForName:entity inManagedObjectContext:myNSMO.managedObjectContext] insertIntoManagedObjectContext:nil]; 它可以工作,但不适合我的应用设计(无需详细说明)

    使用[myNSMO dictionaryWithValuesForKeys:<#(NSArray *)#>]NSManagedObject 生成NSDictionary。这不行,因为它返回一个包含 NSManagedObject 字段地址的字典。

    创建一个 NSDictionary 使用 copyWithZone 填充每个键值,如下所示 [myDictionary setObject:[myNSMO.field copyWithZone:nil] forKey:@"Key"]; 也不行,我还是得到字段地址...

    手动输入每个字段 [myDictionary setObject:[NSString stringWithFormat:@"%@",myNSMO.field ] forKey:@"Key"]; 这次很好,我确实得到了新的内存分配。但是手动编写代码非常耗时...

是否有人找到了聪明的方法来做到这一点?选项 1) 不起作用的原因是因为我将字典用作队列。我首先存储对象的副本,然后在需要时弹出条目。然后将该特定字典条目的副本返回到询问方法。问题是我无法创建使用 [[...] insertIntoManagedObjectContext:nil]; 创建的 NSManagedObject 的副本

有什么解决办法吗?

【问题讨论】:

【参考方案1】:

在大多数意义上保持指向托管对象字段的强指针是安全的——关系是特殊的,但日期、字符串和数字的实际 Foundation 对象是普通对象,如果您有强引用,它们将保留在内存中。

话虽如此,要创建包含实体所有属性的字典副本,您可以执行以下操作:

NSArray *properties = [[object entity] properties];
NSMutableDictionary *dictionaryRepresentation = [NSMutableDictionary dictionary];
for(NSAttributeDescription *attribute in properties)

    // we want only actual attributes, not relationships
    // or fetched properties
    if([attribute isKindOfClass:[NSAttributeDescription class]])
    
        [dictionaryRepresentation
                 setObject:[object valueForKey:attribute.name]
                 forKey:attribute.name];
    

因此,您正在使用托管对象公开其实体描述的事实,其中包括属性列表,将这些属性缩减为仅属性,然后使用键值编码来获取每个属性的当前值和最后将其插入字典中。

如果出于某种原因您确实想要属性的副本 - 不过,正如我所说,绝对没有理由这样做 - 您会 copy(如果您不使用 ARC,则为 autorelease)每个属性将其插入字典时。

【讨论】:

感谢代码片段,帮助很大!不知道为什么,但我仍然得到对核心数据字段的引用。在循环中,如果我设置 [dictionaryRepresentation setObject:[photo valueForKey:[attribute.name copy]] forKey:attribute.name];然后查看我的堆栈: (lldb) p photo.secret (NSString ) $1 = 0x0aaea560 @"50d19b9296" (lldb) p (NSString)[dictionaryRepresentation valueForKey:@"secret"] (NSString *) $2 = 0x0aaea560 @"50d19b9296"。两者都有相同的地址... 更新:如果我使用 [dictionaryRepresentation setObject:[NSString stringWithFormat:@"%@",[photo valueForKey:attribute.name]] forKey:attribute.name],那么它是一个新的内存块,正是我想要的。谢谢! Tommy,抱歉,我在哪里检查您的答案是否已被接受? 令人尴尬的是,我从来没有真正问过问题,所以我无能为力。至于copyretain 具有相同的结果,我想这是无论如何都不可变的对象使用的内部优化。正如我一直说的,真的没有必要复制。 关于副本,有两个原因。 1) 属性用于数据展示;同时,还有一个维护bckgrd线程。使用 CD 委托在下一个视图上进行合并。 2)数据被发送到其他视图控制器,我倾向于保留对创建它们的视图的引用,这使 mem mgt 更容易。最后,它一次只有一行,超过数百,所以开销很低(如果我复制整个数据库就不会出现这种情况)我这样做只是为了避免昂贵的优化和应用程序崩溃的边缘情况: p 谢谢!

以上是关于创建 NSManagedObject 的副本的主要内容,如果未能解决你的问题,请参考以下文章

c_cpp NSManagedObject类别,用于在另一个上下文中创建深层副本

NSManagedObject 的副本

无论当前上下文状态如何,如何获取 NSManagedObject 的持久存储副本

es指定分片以及分片副本数

如何观察 NSManagedObject 是不是从 managedObjectContext 中移除

创建新的 NSManagedObject 并将其分配给新的 NSManagedObject *有时*会失败