使用SDWebImage的多线程导致NSManagedObjects出现两次

时间:2014-03-17 20:21:48

标签: ios multithreading core-data nsmanagedobject sdwebimage

我有以下问题。我目前正在构建基于配方的应用程序,并使用标准的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进行线程处理非常棘手,我已经尝试了几种方法以使其工作,但到目前为止还没有任何工作。任何提示都非常感谢!

1 个答案:

答案 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 dataan in-depth post