Core Data不保存可转换的NSMutableDictionary

Mar*_*arc 4 core-data objective-c nsmanagedobjectcontext ios

我有两个类:Profile和Config.配置文件包含NSSet的Config对象.Profile和Config都是NSManagedObject子类.

@interface Profile : NSManagedObject

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

- (void)print;

@end
Run Code Online (Sandbox Code Playgroud)

这是Config类

@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
Run Code Online (Sandbox Code Playgroud)

字典myDict有NSString*键和值.现在当我对myDict进行任何更改时,我调用了NSManagedObjectsave方法,并且没有任何错误.只要我不杀死应用程序,一切都按预期运行.

但是当我强制杀死应用程序时(无论是在Xcode中还是通过双击主页按钮并在底部的按钮行中将其删除)然后重新启动应用程序,myDict中的数据将恢复为之前的状态,即新的数据实际上没有保存.它似乎只是在我杀死应用程序之前保存.

myDict在xcdatamodeld文件中列为Transformable.我没有指定任何NSTransformer课程就试过了.我也尝试过指定一个变换器类MyDictTransformer,在Config中我添加了这段代码:

在Config.h中:

@interface MyDictTransformer : NSValueTransformer

@end
Run Code Online (Sandbox Code Playgroud)

在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
Run Code Online (Sandbox Code Playgroud)

另外在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"];
    }
}
Run Code Online (Sandbox Code Playgroud)

同样在AppDelegate中,我applicationDidEnterBackground和两个人都applicationWillTerminate打电话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();
        } 
    }
}
Run Code Online (Sandbox Code Playgroud)

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

A)我做错了什么?B)我怎样才能解决这个问题,即使我必须使用其他数据结构而不是NSMutableDictionary保存数据?

小智 21

你已宣布myDictNSMutableDictionary一个大红旗.

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

有可能,你正在使用myDict这样的东西:

someConfig.myDict[@"someKey"] = @"someValue";
[context save:&error];
Run Code Online (Sandbox Code Playgroud)

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

严格地说,[someConfig didChangeValueForKey:@"myDict"]每次改变时你都可以随时打电话myDict.我不推荐它,因为它很容易忘记并且容易出错.

最好将声明声明myDict为不可变并使用它如下:

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