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

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

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

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

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

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

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

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

有什么解决办法吗?

【问题讨论】:

    标签: ios core-data nsdictionary 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 谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-08
    • 1970-01-01
    相关资源
    最近更新 更多