4

Post と呼ばれるエンティティと User と呼ばれるエンティティの 2 つがあります。Post<<---->User はコア データの関係です。NSFetchedResultsController を使用してコア データ スタック内のすべての Post レコードを取得し、それらを UITableView に表示しています。各セルには画像があり、その画像は User.profilePicture に対応します。

初期化時に、サーバーからプロファイル画像をダウンロードせず、そのセルをスクロールしたときにのみダウンロードします (遅延ロード)。ダウンロードしたら、ダウンロードしたイメージをコア データ スタックの対応する User.profilePicture に保存します。

User エンティティを更新するときに 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"];
}

これにより、Post 要素に変更があることが FRC に通知されます。

ここで追加情報を見つけることができます

編集:

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 を使用し、オブザーバーを User エンティティに追加し、それに応じて対応する画像ビューを更新します。しかし、KVO のコードはかなり複雑です。ReactiveCocoa はそれらを簡素化できます。

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