NSFetchedResultsController多个实体为UITableView [英] NSFetchedResultsController multiple entities for UITableView

查看:171
本文介绍了NSFetchedResultsController多个实体为UITableView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



当我更新用户时,是否有一个方法调用controllerDidChangeContent实体??我目前的理解是,我的NSFetchedResultsController只能跟随Post实体,因为这是我最初设置它做,不能遍历和监视关系之间的更新,是真的吗?



在您的用户 .m文件实现 setProfilePicture:如下:

  //在多个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元素已更改。



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



编辑:



要获取访问数据,您可以将其添加到您的用户 .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;
//这通过使用单个队列
//来解决所有配置文件图片下载的每个项目的多个下载。
//有更多的并发方法来完成
dispatch_async(downloadSerialQueue,^ {//定义一些串行队列,以确保你多次下载同一个对象
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 = // [从服务器检索数据的方法];
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;
}


I have two entities one called Post and one called User. Post<<---->User is the relationship in core data. I am using a NSFetchedResultsController to fetch all Post records in my core data stack and then displaying them in a UITableView. Each cell has an image and that image corresponds to a User.profilePicture.

Upon initializing I do not download the profile picture from the server, I only download when it scrolls past that cell (lazy load). Once I download it I save the downloaded image to the corresponding User.profilePicture in the core data stack.

Is there a way for controllerDidChangeContent to be called when I update the User entity?? My current understanding is that my NSFetchedResultsController can only follow the Post entity since that is what I initially set it to do and cannot traverse and monitor updates across a relationship, is that true?

解决方案

Sadly I know only of an UGLY solution for this issue.

In your User .m file implements the setProfilePicture: like this:

//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"];
}

This will notify the FRC that the Post element has changes.

You might find additional information here

Edit:

To fetch the data on access you can add this to your 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;
}

这篇关于NSFetchedResultsController多个实体为UITableView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆