【问题标题】:Core Data not saving transformable NSMutableDictionary核心数据不保存可转换的 NSMutableDictionary
【发布时间】:2014-04-08 07:55:36
【问题描述】:

我有两个类:Profile 和 Config。 Profile 包含一个 NSSet 的 Config 对象。 Profile 和 Config 都是 NSManagedObject 的子类。

@interface Profile : NSManagedObject

@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSSet *configs;

- (void)print;

@end

这里是配置类

@interface Config : NSManagedObject

@property (nonatomic, retain) NSString * otherdata;
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSMutableDictionary *myDict;
@property (nonatomic, retain) Profile *profile;

- (void)print;

@end

字典 myDict 有 NSString *键和值。现在,当我对 myDict 进行任何更改时,我会调用 NSManagedObject save 方法,它可以正常工作,没有错误。只要我不杀死应用程序,一切都会按预期运行。

但是当我强制终止应用程序(在 Xcode 中或通过双击主页按钮并在底部的按钮行中终止它)然后重新启动应用程序时,myDict 中的数据恢复到之前的数据,即新数据实际上并未保存。它似乎只是在我杀死该应用程序之前才被保存。

myDict 在 xcdatamodeld 文件中被列为可转换。我在没有指定任何NSTransformer 类的情况下尝试了它。我还尝试了指定一个转换器类 MyDictTransformer,并在 Config 中添加了以下代码:

在 Config.h 中:

@interface MyDictTransformer : NSValueTransformer

@end

在 Config.m 中:

@implementation MyDictTransformer

+ (Class)transformedValueClass
{
    return [NSMutableDictionary class];
}

+ (BOOL)allowsReverseTransformation
{
    return YES;
}

- (id)transformedValue:(id)value
{
    return [NSKeyedArchiver archivedDataWithRootObject:value];
}

- (id)reverseTransformedValue:(id)value
{
    return [NSKeyedUnarchiver unarchiveObjectWithData:value];
}

@end

在 Config.m 的顶部我也有这个:

//
// from: http://stackoverflow.com/questions/4089352/core-data-not-updating-a-transformable-attribute
//

+ (void)initialize {
    if (self == [Config class]) {
        MyDictTransformer *transformer = [[MyDictTransformer alloc] init];
        [NSValueTransformer setValueTransformer:transformer forName:@"MyDictTransformer"];
    }
}

同样在 AppDelegate 中,在 applicationDidEnterBackgroundapplicationWillTerminate 中我都调用 saveContext:

- (void)saveContext
{
    NSError *error = nil;
    NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    if (managedObjectContext != nil)
    {
        if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error])
        {
            /*
             Replace this implementation with code to handle the error appropriately.

             abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 
             */
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        } 
    }
}

无论我尝试了什么,它根本不会将字典保存在 Config 中。它会保存 config.name 之类的任何其他更改,但不会保存在 config.myDict 中。

A) 我做错了什么? B) 即使我必须使用 NSMutableDictionary 以外的其他数据结构来保存数据,我该如何解决这个问题?

【问题讨论】:

  • 所以您在进行更改后显式调用saveContext?你只有一个managedObjectContext吗?
  • 首先,NSDictionary 符合 NSCoder,因此您不需要自定义转换器。你可以使用标准的。听起来您并没有真正保存数据。你使用什么样的堆栈?主队列上的单个 MOC、嵌套的子/父、UIManagedDocument 还是其他?
  • 是的,我只有一个 managedObjectContext。它是我在 AppDelegate 中创建的单个对象。我什至实时检查 managedObjectContext 是否有父级。它没有。

标签: ios objective-c core-data nsmanagedobjectcontext


【解决方案1】:

您已将myDict 声明为NSMutableDictionary,这是一个很大的危险信号。

托管对象属性应该从不是可变类型

很有可能,您正在使用 myDict 类似的东西:

someConfig.myDict[@"someKey"] = @"someValue";
[context save:&error];

问题是,您没有调用someConfig 的setter 方法,因此您没有做任何事情来通知它属性已更改。即使您调用save:,上下文也不会打扰保存未更改的对象。

严格来说,每次更改myDict 时,您都可以调用[someConfig didChangeValueForKey:@"myDict"]。不过我不推荐它,因为它很容易忘记并且容易出错。

最好将myDict 声明为不可变并像这样使用它:

@property (nonatomic, retain) NSDictionary *myDict;
...
NSMutableDictionary *updatedDict = [someConfig.myDict mutableCopy];
updatedDict[@"someKey"] = @"someValue";
someConfig.myDict = [updatedDict copy];
[context save:&error];

【讨论】:

  • 太棒了太棒了! NSDictionary 方法效果很好。先生,您是IOS编程之神。
  • 帮了我,正是我的问题+1
  • 非常感谢。无法摆脱didChangeValueForKey,所以我不得不在模型中使用非可变字典并创建一个 mutableCopy 进行修改。
  • 致电willChangeValueForKey:,进行更改,然后致电didChangeValueForKey: 不就足够了吗?不幸的是,它对我不起作用。我想我必须使用 NSDictionary 方法并在设置值时制作可变副本。不过,必须这样做似乎很疯狂。不幸的是,这需要额外的内存。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-30
  • 1970-01-01
  • 2011-08-11
  • 1970-01-01
  • 2014-03-09
  • 1970-01-01
相关资源
最近更新 更多