我有一个书店,为简单起见,它有两个属性。
bookTitle
和模型NSManagedObject
bookAuthor
和模型中的媒体资源名称为: NSManagedObject
。我有一本书可能只有在没有重复的情况下才需要添加。该数组称为possibleBooksToSaveToArray
这是我效率低下的方法:
bookEntry
bookTitle
和bookAuthor
的每个实例。insert
请求时不会保存它。以下是代码:
-(BOOL)saveUniqueBookEntriesWithArray:(NSArray*)array withCompletionBlock:(void(^)(NSError *error))completionBlock{
NSMutableArray *possibleBooksToSaveToArray = [array mutableCopy];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:NSStringFromClass([BookEntry class]) inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSError *error = nil;
NSArray *result = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
NSMutableArray *booksAlreadyInDatabaseNoNeedToSaveArray = [[NSMutableArray alloc] init];
if([result count] > 0){
for(int i = 0; i < [possibleBooksToSaveToArray count]; i++){
for(int k = 0; k < [result count]; k++){
RSSBookEntryModel * currentPossibleBookEntry = possibleBooksToSaveToArray[i];
BookEntry * currentDBObject = result[k];
NSString *cbemTitle = [currentPossibleBookEntry.bookTitle lowercaseString];
NSString *cbemAuthor = [currentPossibleBookEntry.bookAuthor lowercaseString];
NSString *dbTitle = [currentDBObject.bookTitle lowercaseString];
NSString *dbAuthor = [currentDBObject.bookAuthor lowercaseString];
if([cbemTitle isEqualToString:dbTitle] && [cbemAuthor isEqualToString:dbAuthor]){
[booksAlreadyInDatabaseNoNeedToSaveArray addObject:currentPossibleBookEntry];
break;
}
}
}
}
[possibleBooksToSaveToArray removeObjectsInArray:booksAlreadyInDatabaseNoNeedToSaveArray];
}
//Now run Insert into database code for updated narrowed down array called possibleBooksToSaveToArray
这很好但我知道这可以用谓词来完成。我已经将谓词用于单个属性,但我不知道如何通过数组实现这一点。
有人可以帮助我吗?
谢谢
答案 0 :(得分:1)
只需使用IN
运算符即可使用数组执行搜索。因此,查看数组possibleBooksToSaveToArray
并假设它是一个对象数组,我们可以使用关键路径“bookTitle”轻松提取标题,我们可以这样做:
NSArray *bookTitlesToAdd = [possibleBooksToSaveToArray valueForKey:@"bookTitle"];
//now we have an array of titles we can fetch against.
//If we want only the books that are missing:
NSFetchRequest *existingBooksFetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([BookEntry class])];
existingBooksFetchRequest.predicate = [NSPredicate predicateWithFormat:@"bookTitle in %@",bookTitlesToAdd];
NSDictionary *existingBooksKeyedByTitle;
NSArray *existingBooks = [context executeFetchRequest:existingBooksFetchRequest error:nil];
if (existingBooks.count > 0) {
existingBooksKeyedByTitle = [NSDictionary dictionaryWithObjects:existingBooks forKeys:[existingBooks valueForKey:@"bookTitle"]];
}
此时我们现在有一本BookEntry托管对象的字典,这些对象由他们的图书标题键入。这使得迭代书籍更容易添加。
for (NSDictionary *bookToAdd in possibleBooksToSaveToArray) {
BookEntry *existingBookEntry = existingBooksKeyedByTitle[bookToAdd[@"bookTitle"]];
if (!existingBookEntry) {
//we need to add a new book
} else {
//we update an existing book
}
}
如果您想执行大小写和变音符号不敏感搜索,那么您可以做的是将谓词更改为:
[NSPredicate predicateWithFormat:@"bookTitle in [cd]%@",bookTitlesToAdd]
如果您想使用作者和书籍标题进行检查,那么我建议您保留每本书的ISBN号或某种形式的规范标识。即使在SQL中,我也不相信它可以创建一个相同匹配两列的谓词。
像[NSPredicate predicateWithFormat:@"bookTitle in %@ && bookAuthor in %@",bookTitlesToAdd,bookAuthorsToAdd]
之类的东西会起作用,但是当你期望作者B时,你仍然会得到作者A写的书X,因为作者A在你提供的作者数组中。
所以我绝对推荐使用ISBN方法,否则您也可以将谓词添加到谓词中,并在迭代数组时简单地验证每本书。我认为有多个作者同名书籍的机会非常小,所以你不必过于担心。
答案 1 :(得分:0)
我已经重构了你的代码,以展示我是如何做出类似的事情的。
对每个条目执行获取请求。如果我正确阅读文档,您的ManagedObjectModel已经在内存中,因此不会对性能产生影响。你的内存使用量实际上应该下降。
-(void)saveUniqueBookEntriesWithArray:(NSArray*) possibleBooksToSaveToArray withCompletionBlock:(void(^)(NSError *error))completionBlock {
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([BookEntry class])];
fetchRequest.entity:entity;
NSError *error = nil;
NSArray result;
for (RSSBookEntryModel *bookEntry in possibleBooksToSaveToArray)
{
fetchRequest.predicate = [NSpredicate predicateWithFormat:@"BookTitle = %@ && BookAuthor = %@", bookEntry.bookTitle, bookEntry.bookAuthor];
result = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (result.count < 1)
{
// Save new book to the database
} else
{
// Book already exists in the database.
}
}
}
希望有所帮助。