Skip to content

Instantly share code, notes, and snippets.

@tonnylitao
Last active August 29, 2015 13:57
Show Gist options
  • Save tonnylitao/9657887 to your computer and use it in GitHub Desktop.
Save tonnylitao/9657887 to your computer and use it in GitHub Desktop.
CoreData Entity ImportFromApi, before import(Find-or-Create), we delete local not exist data first.
//
// NSManagedObject+ImportFromApi.m
// ThermometerBLE
//
// Created by Tonny on 3/4/14.
// Copyright (c) 2014 Doouya. All rights reserved.
//
#import "NSManagedObject+ImportFromApi.h"
#import "CommunityHeader.h"
@implementation NSManagedObject (ImportFromApi)
+ (void) DY_importFromArray:(NSArray *)array completion:(DYIndexBlock)completion
{
[self DY_importFromArray:array importBlock:nil deletePredicateBlock:nil completion:completion];
}
+ (void) DY_importFromArray:(NSArray *)array importBlock:(DYTwoObjectBlock)importBlock deletePredicateBlock:(DYPredicateBlock)predicateBlock completion:(DYIndexBlock)completion{
#ifdef DEBUG
__block NSPredicate *deletePre = nil;
NSDate *startD = [NSDate date];
NSMutableArray *needUpdateIds = [NSMutableArray arrayWithCapacity:array.count];
NSMutableArray *add = [NSMutableArray arrayWithCapacity:array.count];
#endif
NSUInteger count = array.count;
[NSManagedObjectContext childSaveWithBlock:^(NSManagedObjectContext *localContext) {//use default context instead of child of root context
NSAttributeDescription *primaryAttribute = [[self MR_entityDescription] MR_primaryAttributeToRelateBy]; //topicId
NSString *key = [primaryAttribute name]; //topicId
if (predicateBlock) { //delete
NSPredicate *pre = nil;
if (count > 0) {
id first = [[array firstObject] MR_valueForAttribute:primaryAttribute];
id last = [[array lastObject] MR_valueForAttribute:primaryAttribute];
NSInteger max = MAX([first integerValue], [last integerValue]);
NSInteger min = MIN([first integerValue], [last integerValue]);
NSArray *values = [array valueForKeyPath:[[primaryAttribute userInfo] valueForKey:kMagicalRecordImportAttributeKeyMapKey]]; //id
pre = predicateBlock(key, min, max, values, localContext);
}else{ //0
pre = predicateBlock(key, 0, 0, nil, localContext);
}
if (pre) {
#ifdef DEBUG
SLLog(@"delete pre %@", pre);
deletePre = pre;
NSArray *deleted = [self MR_findAllWithPredicate:pre inContext:localContext];
SLog(@"Import Delete %@ %@", NSStringFromClass([self class]), [[deleted valueForKeyPath:key] componentsJoinedByString:@","]);
#endif
[self MR_deleteAllMatchingPredicate:pre inContext:localContext];
}
}
if (count > 0) {
///update
NSArray *allIds = [array valueForKeyPath:@"id"];
NSPredicate *updatePre = [NSPredicate predicateWithFormat:@"%K IN %@", key, allIds];
NSArray *exist = [self MR_findAllWithPredicate:updatePre inContext:localContext];
NSMutableArray *needUpdate = exist.count>0?[exist mutableCopy]:nil;
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
id Id = obj[@"id"];
NSManagedObject *mamObj = nil;
if (needUpdate && needUpdate.count > 0) { //update
NSInteger location = [[needUpdate valueForKeyPath:key] indexOfObject:Id];
if (location != NSNotFound) {
mamObj = needUpdate[location];
[needUpdate removeObject:mamObj];
#ifdef DEBUG
[needUpdateIds addObject:Id];
#endif
}
}
if (!mamObj) {
#ifdef DEBUG
[add addObject:Id];
#endif
mamObj = [self MR_createInContext:localContext]; //create
}
[mamObj MR_importValuesForKeysWithObject:obj];
if (importBlock) {
importBlock(obj, mamObj);
}
}];
//delete repeat data
SLog(@"Import Delete Repeate %@ %@", NSStringFromClass([self class]), [[needUpdate valueForKeyPath:key] componentsJoinedByString:@","]);
[needUpdate enumerateObjectsUsingBlock:^(NSManagedObject *obj, NSUInteger idx, BOOL *stop) {
[obj MR_deleteInContext:localContext];
}];
SLog(@"Import Update %@ %@", NSStringFromClass([self class]), [needUpdateIds componentsJoinedByString:@","]);
SLog(@"Import Add %@ %@", NSStringFromClass([self class]), [add componentsJoinedByString:@","]);
}
} completion:^(BOOL success, NSError *error) {
completion(count);
#ifdef DEBUG
if (deletePre) {
NSAssert([self MR_countOfEntitiesWithPredicate:deletePre] == 0, @"Something wrong?");
}
NSTimeInterval intervalD = [startD timeIntervalSinceNow];
SLLog(@"timeInterval %f", ABS(intervalD));
#endif
}];
}
@end
@tonnylitao
Copy link
Author

  1. Delete local data
  2. Find-Or-Create, to update local exist data and create new data
  3. Delete repeat data

Improve:

  1. import in batches to low memory used.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment