这是加载现有的最佳方式,否则创建新的NSManagedObjects?

时间:2015-11-19 08:17:30

标签: ios objective-c core-data nsmanagedobject nsfetchrequest

我需要通过API加载大量数据,并使用它来创建新的或更新现有对象及其关系。这是正确的方法吗?看起来好长时间,我觉得我在这里错过了一些东西。

// Check for existing Object
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:@"Object" inManagedObjectContext:managedObjectContext]];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"name == %@", objectName]];
[fetchRequest setFetchLimit:1];

NSError *error = nil;
NSArray *results = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (results == nil) {
    NSAssert(NO, @"Error executing fetch: %@\n%@", [error localizedDescription], [error userInfo]);
}

Object *object = [results lastObject];

if (object == nil) {
    // Create new object
    object = [NSEntityDescription insertNewObjectForEntityForName:@"Object" inManagedObjectContext:managedObjectContext];
    object.name = objectName;
}


// Check for existing Other
fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:@"Other" inManagedObjectContext:managedObjectContext]];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"name == %@", otherName]];
[fetchRequest setFetchLimit:1];

results = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (results == nil) {
    NSAssert(NO, @"Error executing fetch: %@\n%@", [error localizedDescription], [error userInfo]);
}

Other *other = [results lastObject];

if (other == nil) {
    // Create new Other
    other = [NSEntityDescription insertNewObjectForEntityForName:@"Other" inManagedObjectContext:managedObjectContext];
    other.name = otherName;
}


// Finally
[object addOtherObject:other]; // A many-to-many relationship

if (![managedObjectContext save:&error]) {
    NSAssert(NO, @"Error saving context: %@\n%@", [error localizedDescription], [error userInfo]);
}

所有这些当然都在一个循环中,感觉非常低效。

1 个答案:

答案 0 :(得分:0)

有很多方法可以最大限度地减少样板。我创建了一个NSManagedObject子类,我将其用作所有模型对象的基础。它包含以下方法:

+ (NSString *)entityName;

+ (instancetype)newEntityInContext:(ManagedObjectContext *)context;
+ (instancetype)newEntityInContext:(ManagedObjectContext *)context properties:(NSDictionary *)properties;

+ (NSArray *)entitiesWithPredicate:(NSPredicate *)predicate inContext:(RoundsManagedObjectContext *)context;
+ (NSArray *)entitiesWithPredicate:(NSPredicate *)predicate
                      sortedBy:(NSArray *)sortDescriptors
                     inContext:(ManagedObjectContext *)context;

+ (NSArray *)entitiesWithProperties:(NSDictionary *)properties inContext:(ManagedObjectContext *)context;

+ (NSInteger)countOfEntitiesWithPredicate:(NSPredicate *)predicate inContext:(ManagedObjectContext *)context;

我留给你看看它们如何处理创建获取请求等的样板。它确实使您实际使用核心数据的代码更具可读性。

现在,谈谈在循环中取得的效率:

别。也就是说,不要做个别提取。相反,将objectName收集到一个数组中,一次获取所有相关对象。假设您实现了类似于我上面所写的方法,您可以使用如下所示的伪代码:

NSArray *objectNames = ...;
NSArray *otherNames = ...;

NSManagedObjectContext *context = ...;

NSArray *existingObjects = [Object entitiesWithPredicate:[NSPredicate predicateWithFormat:@"name IN %@", objectNames];
NSArray *existingOthers = [Other entitiesWithPredicate:[NSPredicate predicateWithFormat:@"name IN %@", otherNames];

NSArray *missingObjectNames = [objectNames removeObjects:[existingObjects valueForKeyPath:@"name"]];

for (NSString *name in missingObjectNames) {
    Object *object = [Object newEntityInContext:context];
    object.name = name;

    // Do stuff with Other objects here.
}