【问题标题】:Core Data Entity Relationship Does Not Save Between Launches核心数据实体关系在启动之间不保存
【发布时间】:2011-09-01 00:55:40
【问题描述】:

我正在编写一个应用程序,它有四个主要实体,它们都通过关系链接。有些是一对一的,有些是一对多的。在初始加载时,三个实体将其数据从本地存储的 XML 文件加载到应用程序,其中一个实体从 Web 下载 XML 并从中加载其数据。当应用加载时,它会检查每个文件中的数据是否比当前拥有的数据更新,如果是,它将用相应文件中的数据替换该实体中的所有当前数据。

作为我在编写过程中调试过程的一部分,我一直在强制删除所有数据。当调用删除函数并在应用程序启动时加载所有数据时,应用程序运行良好,所有实体和关系都按应有的方式运行。但是,当我删除对删除函数的调用并执行检查并尝试从其存储的数据中运行时,所有关系似乎都消失了。在调试时,我发现所有实体都包含它们应该包含的所有常规数据,它们只是不再具有关系。我无法弄清楚为什么在世界上这些关系在第一次加载时被保存,但在所有数据都没有重新导入时不保留。

我想有些代码对调试的人会有帮助,但是,我不确定我应该包含多少。因此,我将首先包含数据加载类中调用的方法之一。如果还有其他帮助,请告诉我。非常感谢任何帮助。

更新代码:2/25/11(基于建议 - 问题仍然存在) 更新代码:2/25/11 - 问题已解决

- (NSArray *) loadFeatures {

    if ([self checkForUpdate:@"Features"]) {

        [self deleteAllObjects:@"Features"];

        NSString *filePath = [self dataFilePath:FALSE withResourceName:@"Features"];
        NSData *xmlData = [[NSMutableData alloc] initWithContentsOfFile:filePath];
        NSError *error;
        GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:xmlData options:0 error:&error];

        NSArray *featureElements = [doc.rootElement elementsForName:@"FEATURE"];
        NSMutableSet *featureSections = [[NSMutableSet alloc] init];

        for (GDataXMLElement *featureElement in featureElements) {

            NSString *featureName = nil;
            NSNumber *featureSecure = nil;
            NSNumber *featureID = nil;
            NSNumber *featureSortKey = nil;
            DisplayTypes *featureDisplayType = nil;

            NSArray *names = [featureElement elementsForName:@"NAME"];
            if (names.count > 0) {
                GDataXMLElement *firstName = (GDataXMLElement *) [names objectAtIndex:0];
                featureName = firstName.stringValue;
            } else continue;

            NSArray *secures = [featureElement elementsForName:@"SECURE"];
            if (secures.count > 0) {
                GDataXMLElement *firstSecure = (GDataXMLElement *) [secures objectAtIndex:0];
                featureSecure = [NSNumber numberWithInt:firstSecure.stringValue.intValue];
            } else continue;

            NSArray *featureIDs = [featureElement elementsForName:@"FEATUREID"];
            if (featureIDs.count > 0) {
                GDataXMLElement *firstFeatureID = (GDataXMLElement *) [featureIDs objectAtIndex:0];
                featureID = [NSNumber numberWithInt:firstFeatureID.stringValue.intValue];
            }

            NSArray *featureSortKeys = [featureElement elementsForName:@"SORTKEY"];
            if (featureSortKeys.count > 0) {
                GDataXMLElement *firstSortKey = (GDataXMLElement *) [featureSortKeys objectAtIndex:0];
                featureSortKey = [NSNumber numberWithInt:firstSortKey.stringValue.intValue];
            }

            NSArray *featureDisplays = [featureElement elementsForName:@"DISPLAYTYPEID"];
            if (featureDisplays.count > 0) {
                GDataXMLElement *firstFeatureDisplay = (GDataXMLElement *) [featureDisplays objectAtIndex:0];

                for (DisplayTypes *thisDisplayType in self.displayTypes) {
                    if (thisDisplayType.displayTypeID == [NSNumber numberWithInt:firstFeatureDisplay.stringValue.intValue]) {
                        featureDisplayType = thisDisplayType;
                    }
                }
            }

            NSArray *sectionElements = [featureElement elementsForName:@"SECTIONS"];


            for (GDataXMLElement *sectionElement in sectionElements) {

                NSArray *sectionIDs = [sectionElement elementsForName:@"SECTION"];

                for (GDataXMLElement *sectionID in sectionIDs) {
                    NSArray *thisSectionIDs = [sectionID elementsForName:@"SECTIONID"];
                    if ([thisSectionIDs count]) {
                        GDataXMLElement *thisSectionID = (GDataXMLElement *) [thisSectionIDs objectAtIndex:0];

                        for (Sections *thisSection in self.sections) {

                            if ([thisSection.sectionID isEqualToNumber:[NSNumber numberWithInt:thisSectionID.stringValue.intValue]]) {
                                [featureSections addObject:thisSection];
                            }

                        }
                    }
                }
            }


            NSManagedObjectContext *context = [self managedObjectContext];
            NSManagedObject *featureInfo = [NSEntityDescription insertNewObjectForEntityForName:@"Features" inManagedObjectContext:context];
            [featureInfo setValue:featureName forKey:@"name"];
            [featureInfo setValue:featureSecure forKey:@"secure"];
            [featureInfo setValue:featureID forKey:@"featureID"];
            [featureInfo setValue:featureSortKey forKey:@"sortKey"];
            [featureInfo setValue:featureDisplayType forKey:@"display"];
            [[featureInfo mutableSetValueForKey:@"section"] unionSet:featureSections];

            NSError *error;
            if (![context save:&error]) {
                NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
            }

            [[self.managedObjectContext objectWithID:featureDisplayType.objectID] addFeatureObject:featureInfo];
            [self.managedObjectContext save:&error];

            [featureSections removeAllObjects];


        }

        [xmlData release];
        [doc release];
        [featureSections release];

    }

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Features" inManagedObjectContext:[self managedObjectContext]];
    [fetchRequest setEntity:entity];

    NSError *error;
    NSArray *featureArray = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];

    [fetchRequest release];

    return featureArray;

}

更新:2011 年 5 月 25 日

根据要求,我发布了几个屏幕截图。

1) 这是在删除所有数据并且关系完好无损后加载应用程序时得到的结果

2) 这是我在没有先删除和重新加载数据的情况下再次运行应用程序时得到的结果。底部的选项卡由其中一个实体创建,并且标题略有不同。发生这种情况是因为与 DisplayType 的关系不存在,它不知道要加载哪种类型的视图控制器,也不知道要为选项卡使用哪个图标。

【问题讨论】:

    标签: iphone objective-c cocoa-touch ios core-data


    【解决方案1】:

    通常,您不需要明确设置关系的双方。当您处理一对多关系时,一次将一个实体添加到集合中可能更安全,而不是一次设置所有集合。所以,而不是:

    [featureInfo setValue:[NSSet setWithSet:featureSections] forKey:@"section"];
    

    我会循环遍历featureSections 集合,并将每个对象一一添加到Feature 实体的section 关系中,例如:

    for (Sections *aSection in featureSections) {
        // use the automatically-generated relationship mutator         
        [featureInfo addSectionsObject:aSection];
    }
    

    我希望这会有所帮助...

    否则,Apple 文档中的this section 可能会引起您的兴趣。

    【讨论】:

    • 感谢您的回复。我可以看到的建议的唯一问题是 featureInfo 是 NSManagedObject 类而不是 Features 类的成员,因此没有成员方法“addSectionsObject:” - 我一定会查看文档。跨度>
    • 我确实尝试在获取对象的初始插入下方的代码中实现这一点。我没有将该功能加载为显示功能,而是将 setValue 移至该点。不幸的是,这似乎没有任何效果。
    • 您确实可以访问动态生成的访问器,例如 addSectionsObject:,即使您使用的是 NSManagedObject 实例。 (有关说明以及如何抑制编译器警告,请参阅此内容:developer.apple.com/library/ios/documentation/Cocoa/Conceptual/…)。
    • 请注意,如果您不想使用 CoreData 提供的动态生成的访问器,您可以使用 mutableSetValueForKey: 设置一对多关系的元素,例如:[[featureInfo mutableSetValueForKey:@"section"] unionSet:featureSections];。如果这仍然不起作用,请告诉我。
    • 感谢您的回复。我按照您的建议尝试了此方法,但无济于事。我也有类似的问题,上面几行:[featureInfo setValue:featureDisplayType forKey:@"display"]; - 奇怪的是它会在没有数据时加载并完美设置所有内容。只有在后续发布时才不会保留关系。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-16
    • 1970-01-01
    相关资源
    最近更新 更多