我有以下问题。我目前正在构建基于配方的应用程序,并使用标准的tableview来显示配方。在应用程序启动时,将从包含配方数据的服务器下载文件。然后将数据输入CoreData,确保它是唯一的。同时,我在SDWebImage
中使用cellForRowAtIndexPath
来加载异步。下载图像后,我保存图像并将其路径保存在Recipe
对象中(它是NSManagedObject
)。我还使用UIRefreshControl来刷新tableview以防服务器上有更改(它使用与app启动时相同的机制)。
以下代码的问题是saveImage
功能。行recipe.thumbImage = [NSString...]
导致CoreData出现问题,因为当我使用下拉手势刷新应用程序(从而激活UIRefreshControl)时,配方在tableView中出现两次。如果我删除该行,问题就会消失。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
NSString *imageURL = [@"http://www.example.com" stringByAppendingString:recipe.externalThumbImageURL];
[cell.thumbImageView setImageWithURL:[NSURL URLWithString:imageURL]
placeholderImage:[UIImage imageNamed:@"blankTableviewImage"]
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
if(error) NSLog(@"Error when downloading thumbImage, error: %@", error);
else {
[self saveImage:image forRecipeID:recipe.objectID];
}
}];
}
- (void)saveImage:(UIImage *)image forRecipeID:(NSManagedObjectID *)recipeID
{
if(image) {
ImageHandler *imageHandler = [[ImageHandler alloc] init];
NSError *error;
Recipe *recipe = (Recipe *)[self.recipeDatabase.managedObjectContext existingObjectWithID:recipeID error:&error];
NSString *fileName = [imageHandler getImageName:recipe.externalThumbImageURL];
NSString *localImageDirectory = [imageHandler imageDirectoryPathFromRecipe:recipe];
if (![[NSFileManager defaultManager] fileExistsAtPath:localImageDirectory]) {
[[NSFileManager defaultManager] createDirectoryAtPath:localImageDirectory withIntermediateDirectories:NO attributes:nil error:&error];
}
[imageHandler saveImage:image withFileName:fileName ofType:@"png" inDirectory:localImageDirectory];
recipe.thumbImage = [localImageDirectory stringByAppendingString:[NSString stringWithFormat:@"%@.png", fileName]];
if(error) NSLog(@"Error in saveImage – error: %@", error);
}
}
函数[cell.thumbImageView setImageWithURL:...]
是SDWebImage
的一部分,据我所知,它是异步的。我认为这是问题的一部分。我尝试在recipe.thumbImage
块中包装[recipe.managedObjectContext performBlock:^{}]
,但它也没有帮助。
有没有人提示问题的原因是什么?我知道使用CoreData进行线程处理非常棘手,我已经尝试了几种方法以使其工作,但到目前为止还没有任何工作。任何提示都非常感谢!
答案 0 :(得分:0)
经过一些额外的试验和错误阅读后,我发现在进行这种异步更新时创建子上下文是有意义的。因此,在saveImage
方法中,我现在只需创建一个子上下文并将recipe.thumbImage
包装在[context performBlock:^{}]
中。当我在CoreData中使用UIManagedDocument
时,您必须确保将更改写入文件。
这是代码
- (void)saveImage:(UIImage *)image forRecipeID:(NSManagedObjectID *)recipeID
{
if(image) {
NSError *error;
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
context.parentContext = self.document.managedObjectContext;
Recipe *recipe = (Recipe *)[context existingObjectWithID:recipeID error:&error];
...
[context performBlock:^{
recipe.thumbImage = [localImageDirectory stringByAppendingString:[NSString stringWithFormat:@"%@.png", fileName]];
[context save:nil];
[self.document saveToURL:document.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:nil];
}];
}
}
这里还有一个good thread with more comments on multi-threading and core data和an in-depth post