Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/96.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 核心数据未保存可转换NSMutableDictionary_Ios_Objective C_Core Data_Nsmanagedobjectcontext - Fatal编程技术网

Ios 核心数据未保存可转换NSMutableDictionary

Ios 核心数据未保存可转换NSMutableDictionary,ios,objective-c,core-data,nsmanagedobjectcontext,Ios,Objective C,Core Data,Nsmanagedobjectcontext,我有两个类:Profile和Config。配置文件包含一组配置对象。Profile和Config都是NSManagedObject子类 @interface Profile : NSManagedObject @property (nonatomic, retain) NSString * name; @property (nonatomic, retain) NSSet *configs; - (void)print; @end 下面是Config类 @interface Config

我有两个类:Profile和Config。配置文件包含一组配置对象。Profile和Config都是
NSManagedObject
子类

@interface Profile : NSManagedObject

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

- (void)print;

@end
下面是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
字典myDict具有
NSString
*键和值。现在,当我对myDict进行任何更改时,我调用
NSManagedObject
save方法,该方法工作正常,没有错误。只要我不杀掉这个应用程序,一切都会正常运行

但是,当我强制关闭应用程序(在Xcode中或通过双击home按钮并关闭底部一行按钮)然后重新启动应用程序时,myDict中的数据会恢复到以前的状态,即新数据实际上没有保存。它似乎是在我关闭应用程序之前保存的

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

在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中,在
ApplicationIdentinterBackground
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();
        } 
    }
}
无论我尝试了什么,它都无法将字典保存在Config中。它会保存config.name中的任何其他更改,但不会保存config.myDict中的更改

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

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

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

很有可能,您正在使用类似以下内容的
myDict

someConfig.myDict[@"someKey"] = @"someValue";
[context save:&error];
@property (nonatomic, retain) NSDictionary *myDict;
...
NSMutableDictionary *updatedDict = [someConfig.myDict mutableCopy];
updatedDict[@"someKey"] = @"someValue";
someConfig.myDict = [updatedDict copy];
[context save:&error];
问题是,您没有调用
someConfig
的setter方法,因此您没有做任何事情来通知它属性已更改。即使您正在调用
save:
,上下文也不会麻烦保存未更改的对象

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

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

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

所以在进行更改后,您显式调用了
saveContext
?您是否只有一个
managedObjectContext
?首先,
NSDictionary
NSCoder
兼容,因此您不需要自定义转换器。你可以用标准的。听起来您并没有真正保存数据。您使用的是哪种堆栈?主队列上的单个MOC、嵌套的子/父、UIManagedDocument或其他内容?是的,我只有一个managedObjectContext。它是我在AppDelegate中创建的单个对象。我甚至实时检查managedObjectContext是否有父对象。没有,太棒了!NSDictionary方法非常有效。先生,你是IOS编程之神。帮助我,正是我的问题。无法摆脱
didChangeValueForKey
,因此我不得不在模型中使用一个不可变的字典,并创建一个可变副本进行修改。调用
willChangeValueForKey:
,进行更改,然后调用
didChangeValueForKey:
,难道还不够吗?不幸的是,这对我不起作用。我想我必须使用NSDictionary方法,并在设置值时创建可变副本。但这样做似乎很疯狂。不幸的是,这需要额外的内存。
[updatedict copy]
为我做了这件事。