4

我有两个实体,一个称为 Post,一个称为 User。Post<<---->User 是核心数据中的关系。我正在使用 NSFetchedResultsController 来获取我的核心数据堆栈中的所有 Post 记录,然后在 UITableView 中显示它们。每个单元格都有一个图像,该图像对应一个 User.profilePicture。

初始化时,我不从服务器下载个人资料图片,我只在滚动经过该单元格时下载(延迟加载)。下载后,我将下载的图像保存到核心数据堆栈中相应的 User.profilePicture 中。

当我更新用户实体时,有没有办法调用 controllerDidChangeContent?我目前的理解是,我的 NSFetchedResultsController 只能跟随 Post 实体,因为这是我最初设置它的目的,并且不能遍历和监视关系中的更新,是这样吗?

4

2 回答 2

4

可悲的是,我只知道这个问题的一个丑陋的解决方案。

在您的User.m 文件中实现setProfilePicture:如下:

//NOT TESTED IN A MULTITHREADED ENV
- (void) setProfilePicture:(NSData *)data
{
    [self willChangeValueForKey:@"profilePicture"];
    [self setPrimitiveValue:data forKey:@"profilePicture"];
    [self.posts enumerateObjectsUsingBlock:^(Post* p, BOOL *stop) {
        [p willChangeValueForKey:@"user"];
        [p didChangeValueForKey:@"user"];
    }];
    [self didChangeValueForKey:@"profilePicture"];
}

这将通知 FRC Post 元素发生了变化。

您可能会在此处找到更多信息

编辑:

要获取访问数据,您可以将其添加到您的User.m:

//UNTESTED
+ (void) mergeToMain:(NSNotification*)notification
{
    AppDelegate* appDel = (AppDelegate*)[[UIApplication sharedApplication] delegate];
    [appDel.managedObjectContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:) 
                                                  withObject:notification 
                                               waitUntilDone:YES];
}

- (NSData*)_profilePicture
{
    return [self primitiveValueForKey:@"profilePicture"];
}

- (NSData*) profilePicture
{
    [self willAccessValueForKey:@"profilePicture"];
    NSData* picData = [self primitiveValueForKey:@"profilePicture"];
    if (!name) {
        __block NSManagedObjectID* objectID = self.objectID;
        //This solves the multiple downloads per item by using a single queue
        //for all profile pictures download.
        //There are more concurrent ways to accomplish that
        dispatch_async(downloadSerialQueue, ^{ //define some serial queue for assuring you down download multiple times the same object
            NSError* error = nil;
            AppDelegate* appDel = (AppDelegate*)[[UIApplication sharedApplication] delegate];
            NSManagedObjectContext* context = [[NSManagedObjectContext alloc] init];
            [context setPersistentStoreCoordinator:appDel.persistentStoreCoordinator];
            [context setUndoManager:nil];
            User* user = (User*)[context existingObjectWithID:objectID error:&error];
            if (user && [user _profilePicture] == nil) {
                NSData *data = //[method to retrieve data from server];
                if (data) {
                    if (user) {
                        user.profilePicture = data;
                    } else {
                        NSLog(@"ERROR:: error fetching user: %@",error);
                        return;
                    }
                    [[NSNotificationCenter defaultCenter] addObserver:[self class] selector:@selector(mergeToMain:) name:NSManagedObjectContextDidSaveNotification object:context];
                    [context save:&error];
                    [[NSNotificationCenter defaultCenter] removeObserver:[self class] name:NSManagedObjectContextDidSaveNotification object:context];
                }                    
            }
        });
    }
    [self didAccessValueForKey:@"profilePicture"];
    return picData;
}
于 2013-04-26T18:45:46.867 回答
-2

我认为这个问题可以在不涉及 NSFetchedResultsController 的情况下解决。

  1. 使用SDWebImage, SDWebImage 可以从远程服务器异步加载图像,只需这样做:

    [myImageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]
                   placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
    
  2. 使用 KVO,将观察者添加到用户实体并相应地更新相应的图像视图。但是 KVO 的代码比较复杂,ReactiveCocoa可以简化它们:

    [RACAble(user.profilePicture) subscribeNext:^(UIImage *image) {
        [myImageView setImage:image];
    }];
    
于 2013-04-26T17:58:59.040 回答