首页 文章

NSFetchedResultsController用于UITableView的多个实体

提问于
浏览
4

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

在初始化时,我不从服务器下载配置文件图片,我只在它滚过该单元格时下载(延迟加载) . 下载后,我将下载的图像保存到核心数据堆栈中相应的User.profilePicture中 .

当我更新User实体时,是否有一种方法可以调用controllerDidChangeContent?我目前的理解是我的NSFetchedResultsController只能跟随Post实体,因为这是我最初设置它并且不能遍历和监视关系中的更新,这是真的吗?

2 回答

  • -2

    可悲的是,我只知道这个问题的UGLY解决方案 .

    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元素有更改 .

    您可能会找到更多信息here

    Edit:

    要获取访问数据,您可以将其添加到 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;
    }
    
  • 4

    我认为这个问题可以在没有涉及NSFetchedResultsController的情况下解决 .

    • 使用SDWebImage,SDWebImage可以异步加载来自远程服务器的图像,只需执行以下操作:
    [myImageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]
                   placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
    
    • 使用KVO,向User实体添加观察者并相应地更新相应的图像视图 . 但是KVO的代码相当复杂,ReactiveCocoa可以简化它们:
    [RACAble(user.profilePicture) subscribeNext:^(UIImage *image) {
        [myImageView setImage:image];
    }];
    

相关问题