尝试将服务器内容同步到 Core Data 时出现问题 - Magical Record 插入过程非常慢
Posted
技术标签:
【中文标题】尝试将服务器内容同步到 Core Data 时出现问题 - Magical Record 插入过程非常慢【英文标题】:Trouble when trying to sync server content into Core Data - Magical Record insertion process is extremely slow 【发布时间】:2014-07-31 07:46:38 【问题描述】:我能够成功地将我的数据库同步到核心数据中。我使用MagicalRecord 作为我的核心数据包装接口。
我面临的问题是插入所有信息的过程真的很慢。 我知道这个问题可能太具体了。但我真的相信我遗漏了 Obj-C 代码中的一些微不足道的东西。
这是我尝试同步的部分数据库的结构
首先是一些背景信息。
每个地方都有:
one(1) 在 place_contact_info 中引用的行 one(1) 在 place_adjustments 中引用的行 七(7)在 place_opening_hours 中引用了行 零(0) 个或多个 在place_tag 和 place_category 中引用了行。数据库(服务器端)目前包含约 1000 个位置。
我在服务器端的 php 脚本以 JSON 格式提供此数据的表示形式。
它的交付方式类似于 this:
这是我对核心数据逻辑的插入。
data
这是上面链接中描述的部分数据库的完整表示。
+ (void)updateDatabaseWithPlaces:(NSDictionary *)data
[FFSynchronizationHandler synchronizePlaces:[data objectForKey:@"places"]];
[FFSynchronizationHandler synchronizeContactInfo:[data objectForKey:@"place_contact_info"]];
[FFSynchronizationHandler synchronizeOpeningHours:[data objectForKey:@"opening_hours"]];
[FFSynchronizationHandler synchronizeAdjustments:[data objectForKey:@"place_adjustments"]];
[FFSynchronizationHandler synchronizeCategories:[data objectForKey:@"place_category"]];
[FFSynchronizationHandler synchronizeTags:[data objectForKey:@"place_tag"]];
[[NSManagedObjectContext MR_defaultContext] MR_saveOnlySelfWithCompletion:^(BOOL success, NSError *error)
[[NSNotificationCenter defaultCenter]postNotificationName:SYNCHRONIZATION_COMPLETE object:nil];
];
+ (void)synchronizePlaces:(NSDictionary*)places
for(id placeParams in places)
Place *place = [Place MR_findFirstByAttribute:@"place_id" withValue:@([[placeParams objectForKey:@"id"]integerValue])];
// if the place is flagged as deleted, delete that entity
if([[placeParams objectForKey:@"is_deleted"]integerValue] == 1)
[place MR_deleteEntity];
continue;
else if(!place)
// if the place does not exists in the database already, create it.
place = [Place MR_createEntity];
place.place_id = @([[placeParams objectForKey:@"id"]integerValue]);
place.name = [placeParams objectForKey:@"name"];
place.longitude = @([[placeParams objectForKey:@"longitude"]floatValue]);
place.latitude = @([[placeParams objectForKey:@"latitude"]floatValue]);
place.main_category = @([[placeParams objectForKey:@"main_category"]integerValue]);
place.info_text = [placeParams objectForKey:@"info_text"] == [NSNull null] ? nil :[placeParams objectForKey:@"info_text"];
[[NSManagedObjectContext MR_defaultContext] MR_saveOnlySelfAndWait];
+ (void)synchronizeContactInfo:(NSDictionary*)contactInfoParams
for(id contactInfo in contactInfoParams)
Place *place = [Place MR_findFirstByAttribute:@"place_id" withValue:@([[contactInfo objectForKey:@"place_id"] integerValue])];
// if the place that the contact info belongs to
// is somehow not here, just continue the loop
if(place == nil)
continue;
PlaceContactInfos *place_contact_info = [PlaceContactInfos MR_createEntity];
place_contact_info.website = [contactInfo objectForKey:@"website"] == [NSNull null] ? nil :[contactInfo objectForKey:@"website"];
place_contact_info.telephone = [contactInfo objectForKey:@"telephone"] == [NSNull null] ? nil : [contactInfo objectForKey:@"telephone"];
place_contact_info.email = [contactInfo objectForKey:@"email"] == [NSNull null] ? nil : [contactInfo objectForKey:@"email"];
place_contact_info.address = [contactInfo objectForKey:@"address"] == [NSNull null] ? nil : [contactInfo objectForKey:@"address"];
place_contact_info.city = [contactInfo objectForKey:@"city"] == [NSNull null] ? nil : [contactInfo objectForKey:@"city"];
place_contact_info.zip_code = [contactInfo objectForKey:@"zip_code"] == [NSNull null] ? nil : [contactInfo objectForKey:@"zip_code"];
place_contact_info.country = [contactInfo objectForKey:@"country"] == [NSNull null] ? nil : [contactInfo objectForKey:@"country"];
place.place_contact_info = place_contact_info;
[[NSManagedObjectContext MR_defaultContext] MR_saveOnlySelfAndWait];
+ (void)synchronizeOpeningHours:(NSDictionary*)openingHoursParams
for(id openingHours in openingHoursParams)
NSNumber* openingHoursId = @([[openingHours objectForKey:@"id"]integerValue]);
NSNumber* placeId = @([[openingHours objectForKey:@"place_id"]integerValue]);
NSNumber* isDeleted = @([[openingHours objectForKey:@"is_deleted"] integerValue]);
Place *place = [Place MR_findFirstByAttribute:@"place_id" withValue:placeId];
// if the place is flagged as deleted, delete that entity
if(isDeleted.integerValue > 0)
PlaceOpeningHours *oh = [PlaceOpeningHours MR_findFirstWithPredicate:[NSPredicate predicateWithFormat:@"place_id = %@ AND oh_id = %@",placeId, openingHoursId]];
if(oh)
[oh MR_deleteEntity];
else
PlaceOpeningHours *oh = [PlaceOpeningHours MR_createEntity];
oh.day = @([[openingHours objectForKey:@"day"]integerValue]);
oh.open = [openingHours objectForKey:@"open"] == [NSNull null] ? nil : [openingHours objectForKey:@"open"];
oh.close = [openingHours objectForKey:@"close"] == [NSNull null] ? nil : [openingHours objectForKey:@"close"];
oh.always_open = @([[openingHours objectForKey:@"always_open"]integerValue]);
oh.is_closed = @([[openingHours objectForKey:@"is_closed"]integerValue]);
oh.place_id = placeId;
oh.place = place;
[[NSManagedObjectContext MR_defaultContext] MR_saveOnlySelfAndWait];
+ (void)synchronizeAdjustments:(NSDictionary*)adjustmentsParams
for(id adjustmentParams in adjustmentsParams)
Place *place = [Place MR_findFirstByAttribute:@"place_id" withValue:@([[adjustmentParams objectForKey:@"place_id"] integerValue])];
// if the place that the adjustments belongs to
// is somehow not here, just continue the loop
if(place == nil)
continue;
PlaceAdjustments *place_adjustments = [PlaceAdjustments MR_createEntity];
place_adjustments.parking = @([[adjustmentParams objectForKey:@"parking"]integerValue]);
place_adjustments.elevator = @([[adjustmentParams objectForKey:@"elevator"]integerValue]);
place_adjustments.toilet = @([[adjustmentParams objectForKey:@"toilet"]integerValue]);
place_adjustments.ramp = @([[adjustmentParams objectForKey:@"ramp"]integerValue]);
place_adjustments.availability = @([[adjustmentParams objectForKey:@"availability"]integerValue]);
[place setPlace_adjustments:place_adjustments];
[[NSManagedObjectContext MR_defaultContext] MR_saveOnlySelfAndWait];
+ (void)synchronizeCategories:(NSDictionary*)placeCategoryParams
for(id categoryParams in placeCategoryParams)
NSNumber* categoryId = @([[categoryParams objectForKey:@"category_id"] integerValue]);
NSNumber* placeId = @([[categoryParams objectForKey:@"place_id"]integerValue]);
NSNumber* isDeleted = @([[categoryParams objectForKey:@"is_deleted"] integerValue]) ;
Place *place = [Place MR_findFirstByAttribute:@"place_id" withValue:placeId];
if(isDeleted.integerValue > 0)
PlaceCategories *cat = [PlaceCategories MR_findFirstWithPredicate:[NSPredicate predicateWithFormat:@"place_id = %@ AND category_id = %@",placeId, categoryId]];
if(cat)
[cat MR_deleteEntity];
else
PlaceCategories *cat = [PlaceCategories MR_createEntity];
cat.category_id = categoryId;
cat.place_id = placeId;
cat.place = place;
[[NSManagedObjectContext MR_defaultContext] MR_saveOnlySelfAndWait];
+ (void)synchronizeTags:(NSDictionary*)placeTagParams
for(id placeTag in placeTagParams)
NSNumber* tagId = @([[placeTag objectForKey:@"id"]integerValue]);
NSNumber* placeId = @([[placeTag objectForKey:@"place_id"] integerValue]);
NSNumber* isDeleted = @([[placeTag objectForKey:@"is_deleted"] integerValue]);
Place *place = [Place MR_findFirstByAttribute:@"place_id" withValue:placeId];
if(isDeleted.integerValue == 1)
PlaceTags *tag = [PlaceTags MR_findFirstWithPredicate:[NSPredicate predicateWithFormat:@"place_id = %@ AND tag_id = %@",placeId, tagId]];
if(tag)
[tag MR_deleteEntity];
else
PlaceTags *tag = [PlaceTags MR_createEntity];
tag.tag = [placeTag objectForKey:@"tag"];
tag.place_id = placeId;
tag.place = place;
[[NSManagedObjectContext MR_defaultContext] MR_saveOnlySelfAndWait];
从第一行代码到
[[NSManagedObjectContext MR_defaultContext] MR_saveOnlySelfWithCompletion:^(BOOL success, NSError *error)
[[NSNotificationCenter defaultCenter]postNotificationName:SYNCHRONIZATION_COMPLETE object:nil];
];
被称为大约一分钟通行证。
如何优化?将其插入 mysql 只需一秒钟。 感谢您的关注。
编辑 1
经过一些分析后,我意识到开放时间和标签的同步需要花费大量时间。
每次运行的MR_findFirstMatchingAttribute
是时间窃贼。您对如何优化有什么建议吗?
【问题讨论】:
你能发布核心数据获取和保存的仪器跟踪吗?时间档案也会很有帮助。 也许第一步是查看 Core Data 的文档并为大部分数据执行批量插入 developer.apple.com/library/ios/documentation/Cocoa/Conceptual/… @quellish 查看我的更新。谢谢 【参考方案1】:看起来您正在主/默认上下文中执行所有操作。这本质上是主线程上下文。通过调用 saveOnlySelfAndWait,您正在阻塞主线程。这可能会导致一些同步锁。我建议创建一个全新的后台上下文,并在那里执行所有保存。
【讨论】:
以上是关于尝试将服务器内容同步到 Core Data 时出现问题 - Magical Record 插入过程非常慢的主要内容,如果未能解决你的问题,请参考以下文章
将 Core Data 添加到现有 Xcode 项目时出现未声明的标识符错误
Core-Data:想要将新的 web xml 内容持久保存到我的数据存储中,而不是替换现有的