MagicalRecord:删除后保存上下文太长
Posted
技术标签:
【中文标题】MagicalRecord:删除后保存上下文太长【英文标题】:MagicalRecord: saving context after deleting is too long 【发布时间】:2015-01-10 22:58:44 【问题描述】:我有下一个问题:我有大约 7000 个实体的数据库,当我需要更新它们(我有我解析的 XML 文件)时,我首先删除所有实体,之后我解析 XML 文件,然后我创建新的实体并保存上下文。早些时候一切都很完美:没有冻结,没有崩溃 - 在 ios 7 上一切都很快。
但是随着 iOS 8 的发布,出现了一些问题:
我通过为所有操作提供一个上下文来解决这个问题:删除、创建和保存。
但是!我有什么:
当我只是在我的设备上安装应用程序时一切顺利:没有删除,只创建实体,7000 个术语和 7 个组被解析得如此之快(在 iPhone 6 上大约 4 秒),保存也很快。
当我在我的 plist 文件中更改数据库版本(增加)时,我的解析器会启动这个算法:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext)
[Term MR_truncateAllInContext:localContext];
[Group MR_truncateAllInContext:localContext];
completion:^(BOOL success, NSError *error)
[self parseTermsInContext:[NSManagedObjectContext contextForCurrentThread] from:self.count];
];
);
“saveWithBlock”方法阻塞线程 1(在分析器中),我的 CPU 加载到 99-108(显然错误)百分比(每次下一次更新保存操作需要越来越多的秒数,从 20 秒到更多,超过 120 秒) .
我已经尝试过这种方式(我为你收集了一种方法中的所有操作):
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
NSManagedObjectContext *localContext = [NSManagedObjectContext contextForCurrentThread];
NSMutableArray *objects = [NSMutableArray arrayWithArray:[Group MR_findAllInContext:localContext]];
[objects addObjectsFromArray:[Term MR_findAllInContext:localContext]];
if (objects && [objects count] > 0)
for (NSManagedObject *object in objects)
[object MR_deleteInContext:localContext];
[localContext MR_saveToPersistentStoreAndWait];
[self parseTermsInContext:localContext from:self.count];
);
这里的操作“MR_saveToPersistentStoreAndWait”也像“saveWithBlock”一样需要很长时间。
我尝试了删除后不保存上下文的方法,即“[localContext MR_saveToPersistentStoreAndWait];”行不存在。这样一来,Groups 和 Terms 也被删除得太快了,后来它们也被解析得太快了,但是保存上下文却太长了。
而且我不知道为什么,但即使我在后台线程保存操作中开始删除和保存进程,也会冻结 UI 线程(在 UI 线程中,我显示的进度从 0 到 100)。当我在这个线程中解析 XML 时,我发送消息以查看一个术语已解析并以百分比设置进度,委托调用方法以在主队列中的 ProgressView 中设置进度。
我没有其他线程可以操作核心数据对象。
与应用程序的工作有链接:http://rghost.ru/60274051 6 秒后:出于测试目的,我启动 NSTimer,它每 0.3 秒用假数据更新进度,以在开始删除和保存操作之前填充进度 50%(更新进度进入主队列)。计时器触发几次,然后保存过程在后台线程中开始,但阻塞主线程(据我所知)并将设置进度操作移动到结束(如果我理解正确的话)。 1:08:然后在保存结束后我开始解析 xml 文件。这是我在删除后保存上下文的线程。您可以看到进度更新。在这个视频中,由于有很多操作,它可以处理错误,但你可以相信我,它可以工作并且看起来很好。解析 7000 个对象后,我再次保存上下文,保存操作不会阻塞 UI 线程。
附加信息: 关系:
【问题讨论】:
【参考方案1】: completion:^(BOOL success, NSError *error)
[self parseTermsInContext:[NSManagedObjectContext contextForCurrentThread] from:self.count];
];
上面的块在主线程中调用(块 UI),所以 contextForCurrentThread == UI 线程
您可以使用 TruncateAll 代替迭代删除所有对象
我的建议是:
// saveWithBlock - already perform block in background thread
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext)
[Term MR_truncateAllInContext:localContext];
[Group MR_truncateAllInContext:localContext];
completion:^(BOOL success, NSError *error)
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext)
// self must be weak!
[self parseTermsInContext:localContext from:self.count];
completion:^(BOOL success, NSError *error)
// Update UI
];
];
【讨论】:
以上是关于MagicalRecord:删除后保存上下文太长的主要内容,如果未能解决你的问题,请参考以下文章
使用 Swift 3 在 Magical Record 中保存上下文时出错