Core Data 不保存对象而且速度很慢

Posted

技术标签:

【中文标题】Core Data 不保存对象而且速度很慢【英文标题】:Core Data doesn't save objects and is slow 【发布时间】:2011-12-23 20:40:18 【问题描述】:

我是第一次使用 Core Data,以斯坦福 ios 应用程序开发课程为指导。我几乎从演示应用程序中复制了代码(当然我根据自己的需要对其进行了调整),但目前我遇到了两个问题。

我的应用程序是一个地图视图,点击一个按钮就会显示一个模态视图控制器。此模式视图检查是否创建了 UIManagedDocument。如果没有,它会创建一个并插入数据。此数据来自属性列表(258 项,所以没有太多)。如果它已经创建(通过先前显示该视图),如果我的逻辑成立,那么假设它也有内容应该是安全的,因为NSManagedObjects 是在创建文档的同时创建的。第一次运行完美无缺,表格加载完毕,我的所有数据都正确显示。

但是,当我关闭然后重新显示我的模态视图时,表格保持为空。我正在检查文档的状态,即UIDocumentStateNormal,所以查询它应该没问题。但事实并非如此:我的 fetchedResultsController 返回 0 行。如果我正确理解UIManagedContext,我遇到的行为可能是由错误/不同的上下文引起的,但我确保:1) 我将我的文档(不仅仅是上下文)传递给prepareForSegue:sender 中的模态视图, 和 2) 当模态视图被解除时,我将带有上下文的文档传递回呈现视图。这就是为什么我认为这可能不是上下文,而是其他东西。

另一件事:在应用程序首次启动时插入 258 条记录在模拟器中已经足够快了。但是,在我的手机上,这可能需要整整 13 秒。插入代码如下所示(为便于阅读而修改):

+ (Department *)departmentName:(NSString *)name
                withAttributes:(NSDictionary *)attributes
                     inContext:(NSManagedObjectContext *)context 

    Department *department = [NSEntityDescription insertNewObjectForEntityForName:@"Department" inManagedObjectContext:context];
        department.name = name;

        NSArray *informationElements = [attributes objectForKey:@"information"];

        for (int i = 0; i < [informationElements count]; i++) 
            NSString *informationValue = [[informationElements objectAtIndex:i] objectForKey:@"value"];

            if ([[[informationElements objectAtIndex:i] objectForKey:@"description"] isEqualToString:@"phone"]) 
                department.phone = informationValue;
             else if ([[[informationElements objectAtIndex:i] objectForKey:@"description"] isEqualToString:@"email"]) 
                department.email = informationValue;
             else if ([[[informationElements objectAtIndex:i] objectForKey:@"description"] isEqualToString:@"web"]) 
                department.website = informationValue;
            
           
    return department;

明确一点:这段代码工作得很好,但它真的很慢。它被封装在一个被精确调用 258 次的方法中。 informationElements 最多包含三个元素,这意味着最多有 258 * 3 = 774 个循环。实际上比这要少得多,但即使是 774,也不应该需要 13 秒,对吧?

下面的sn-p显示UIManagedDocument的初始化:

if (![[NSFileManager defaultManager] fileExistsAtPath:[self.database.fileURL path]]) 
    [self.database saveToURL:self.database.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) 
        [self setupFetchedResultsController];
        [self fetchDepartmentsIntoDocument:self.database];
    ];
 else if (self.database.documentState == UIDocumentStateClosed) 
    [self.database openWithCompletionHandler:^(BOOL success) 
        [self setupFetchedResultsController];
    ];
 else if (self.database.documentState == UIDocumentStateNormal) 
    [self setupFetchedResultsController];

fetchDepartmentsIntoDocument 读取属性列表,然后运行一个循环,为每个属性列表项调用departmentName:withAttributes:inContext

如果有人能给我一些帮助,将不胜感激!

【问题讨论】:

你在不同的线程上试过了吗? 我没有。是否有可能是数据过多而无法足够快地处理? 可能是,我使用核心数据来保存我的单例对象,它工作正常,但你的看起来确实要复杂得多。我说它是一种对有效但缓慢的东西的笼统声明。除非有理由怀疑。 好的,我已将循环限制为仅执行 15 个项目,而且运行速度要快得多,因此我将尝试在线程中运行它。但是,我的数据没有被保存的问题仍然存在。 【参考方案1】:

对于速度问题,我会考虑使用谓词;这应该会大大加快速度!

谓词使上下文仅根据您选择的任何标准返回所需的值。它们更快的原因是它不必将每个存储的实体对象转换为托管对象,而是可以直接从属性中提取,从而大大加快了比较速度。

【讨论】:

是的,这将是一个选项,除了我真的需要所有这些对象。这是一个表格,显示了用户可以从中选择一个的所有部门。如果真的没有办法解决速度问题,我将不得不改变它,但现在我想看看是否还有其他方法可以让我当前的 UI 保持低于一秒的速度。跨度> 【参考方案2】:

当您将 Department 对象插入上下文时,您是否为每个对象保存?插入相对便宜,但保存(即-[NSManagedobjectContext save:])代价高昂(因为数据库必须进行锁定和文件 I/O)。

另外,在风格上,你可以这样做

    for (NSDictionary *element in informationElements) 
        NSString *informationValue = [element objectForKey:@"value"];

        if ([[element objectForKey:@"description"] isEqualToString:@"phone"]) 
            department.phone = informationValue;
         else if ([[element objectForKey:@"description"] isEqualToString:@"email"]) 
            department.email = informationValue;
         else if ([[element objectForKey:@"description"] isEqualToString:@"web"]) 
            department.website = informationValue;
        
       

遍历您的字典数组。

【讨论】:

我实际上依赖于 UIDocument 的自动保存机制,所以我根本没有保存。即使手动保存,我的数据也不会在视图切换之间存储。我也知道快速枚举,但由于我目前的方法也用于讲座,我想我就用那个。

以上是关于Core Data 不保存对象而且速度很慢的主要内容,如果未能解决你的问题,请参考以下文章

Core Data 对象有时不会保存到永久存储中

如何在 RestKit 中保存到 Core Data RKMappingResult 对象?

Core Data 逻辑分布?

在 Core Data (IOS) 中保存数据时出错

如何在通过 Core Data 保存我的 RestKit 托管对象之前对其进行修改?

即使验证失败,Core Data 也会保存对象