这是加载现有的或创建新的 NSManagedObject 的最佳方式吗?
Is this the best way to load existing otherwise create new NSManagedObjects?
我需要通过 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]);
}
所有这些当然都在一个循环中,感觉效率非常低。
有很多方法可以最小化样板文件。我创建了一个 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.
}
我需要通过 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]);
}
所有这些当然都在一个循环中,感觉效率非常低。
有很多方法可以最小化样板文件。我创建了一个 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.
}