核心数据保存时间过长

时间:2014-06-06 09:47:58

标签: ios xcode core-data

我在这里寻找解决方案,例如:

Core Data Saves and UI Performance

Why does Core Data take so long to save an object?

很多人都有我的问题,但我试图使用他们的解决方案失败。

这是我的问题:

我尝试在后台保存核心数据中的10个托管对象。我没有任何错误,所有工作都非常好但是...需要13秒才能保存10个对象!我不知道自己做错了什么......

我需要在我的数据库中保存100个对象,如果只有10个对象需要13秒......我真的很害怕当我尝试节省100时会发生什么。

这是我的代码:

首先,我在后台调用我的保存功能:

[self performSelectorInBackground:@selector(updateMessageList:) withObject:response];

在这里我保存了对象:

- (void)updateMessageList:(NSArray *)messageList
{
    AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
    NSManagedObjectContext *tmpContext = [[NSManagedObjectContext alloc]init];
    tmpContext.persistentStoreCoordinator = [app persistentStoreCoordinator];

    NSError *error;

    int i = 0; //Counter to log how long it takes to insert a managedObject.

    for (MessageReadResponse* messageUpdate in messageList) {    
        NSLog(@"%d", i++);

        Message *message = [NSEntityDescription insertNewObjectForEntityForName:MESSAGE_ENTITY
                                                         inManagedObjectContext:tmpContext];
        [message setState:STATE_ACTIVE];
        [message setFromName:[[messageUpdate from]name]];
        [message setFromSurname:[[messageUpdate from]surname]];
        [message setBody:[messageUpdate body]];
    }

    NSLog(@"Before saving");

    if (![tmpContext save:&error]) {
        ErrorLog(@"%@", error.description);
        [ErrorManagement synchronizeApplication];

        return;
    }

    NSLog(@"After saving");
}

这是我在主线程中合并我的managedObjectContext的地方:

- (void)manageDidSaveNotification:(NSNotification *)notification
{
    NSManagedObjectContext *savedContext = [notification object];

    // Ignore change notifications for the main MOC
    if (__managedObjectContext == savedContext)
    {
        return;
    }

    if (__managedObjectContext.persistentStoreCoordinator != savedContext.persistentStoreCoordinator)
    {
        // That's another database
        return;
    }

    dispatch_sync(dispatch_get_main_queue(), ^{
        [__managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
    });
}

这是我的效果日志:

2014-06-06 11:12:07.207 app-ios-client[260:8017] 0

2014-06-06 11:12:07.210 app-ios-client[260:8017] 1

2014-06-06 11:12:07.217 app-ios-client[260:8017] 2

2014-06-06 11:12:07.219 app-ios-client[260:8017] 3

2014-06-06 11:12:07.221 app-ios-client[260:8017] 4

2014-06-06 11:12:07.255 app-ios-client[260:8017] 5

2014-06-06 11:12:07.257 app-ios-client[260:8017] 6

2014-06-06 11:12:07.259 app-ios-client[260:8017] 7

2014-06-06 11:12:07.289 app-ios-client[260:8017] 8

2014-06-06 11:12:07.293 app-ios-client[260:8017] 9

2014-06-06 11:12:07.304 app-ios-client[260:8017] Before saving

2014-06-06 11:12:20.900 app-ios-client[260:8017] After saving

非常感谢!

编辑:

Here是我的仪器追踪。

已编辑2:

感谢Marcus Zarra,我发现这种方法使我的应用程序运行得太慢了:

-(CGFloat)getLabelHeightForIndex:(NSInteger)index
{
    NSIndexPath *path = [NSIndexPath indexPathForRow:0 inSection:index];

    UITextView *gettingSizeLabel = [[UITextView alloc] init];
    gettingSizeLabel.font = [UIFont fontWithName:@"Helvetica" size:FONT_SIZE];
    gettingSizeLabel.text = [[_fetchedResultsController objectAtIndexPath:path]body];

    Message *info = [_fetchedResultsController objectAtIndexPath:path];
    if ([[info contentSize]isEqualToString:@"(null)"]) {
        CGSize maximumLabelSize = CGSizeMake(LABEL_WIDTH_NO_MEDIA, LABEL_TEXT_MAX_HEIGHT);

        CGSize expectedSize = [gettingSizeLabel sizeThatFits:maximumLabelSize];

        if (expectedSize.height < LABEL_TEXT_MIN_HEIGHT_NO_MEDIA) {
            return LABEL_TEXT_MIN_HEIGHT_NO_MEDIA;
        }

        return  expectedSize.height;
    } else {
        CGSize maximumLabelSize = CGSizeMake(LABEL_WIDTH_MEDIA, LABEL_TEXT_MAX_HEIGHT);

        CGSize expectedSize = [gettingSizeLabel sizeThatFits:maximumLabelSize];

        if (expectedSize.height < LABEL_TEXT_MIN_HEIGHT_MEDIA) {
            return LABEL_TEXT_MIN_HEIGHT_MEDIA;
        }

        return  expectedSize.height;
    }
}

这个方法我曾经知道细胞高度,没有它,应用程序的工作速度非常快。我将考虑如何更快地改变这种方法...

非常感谢Marcus,真实的!

2 个答案:

答案 0 :(得分:4)

这些物体有多大?你想保存多少数据?

您使用什么类型的持久性商店? SQLite的?

保存后,您的UI使用此数据做了什么?您是在进行任何类型的数据解析还是显示数据?

乐器说什么?它说时间花在哪里?

这是第一个问题。

核心数据绝不应该用这么长时间来保存数据。我怀疑你在你的用户界面中正在做的事情是由真正花费时间的保存触发的。仪器中的Time Profiler将告诉我们发生了什么。

虽然我不会按照您的方式编写此代码,但您发布的代码没有任何问题,因此问题必须在其他地方。仪器将告诉我们在哪里看。

更新

感谢您发布跟踪信息,这证实了我的怀疑。如果你看一下花费的时间,你的NSFetchedResultsController中有54%,TimelineViewController花费了20.6%。这意味着保存非常快,然后您的UI会对非常慢慢地对更改做出反应。关闭合并更改通知以确认。从那里我建议深入挖掘你的用户界面及时分析器,找出为什么它如此令人难以置信的慢。

看起来你正在做一些复杂的字符串操作以及那些非常占用CPU的其他东西。解决这些问题,速度会恢复。

答案 1 :(得分:0)

首先,如果您始终将此数量的对象保存到Core Data,请不要为多线程而烦恼。这不会对您的UI性能造成太大影响。尝试在主线程中实现它,就像任何基本教程告诉你的那样。

如果你真的非常想要这个多线程的话,试试看tutorial。您将看到主NSManagedObjectContext适用于您的UI,而任何其他自定义上下文应该用于处理数据。

对我而言,你正试图做一些太好的事情。有时最简单的解决方案是最好的!