NSFetchedResultsController несколько объектов для UITableView
У меня есть две сущности, одна называется Post, а другая - User. Пост<< ---->Пользователь - это связь в основных данных. Я использую NSFetchedResultsController для извлечения всех записей Post из моего основного стека данных, а затем отображаю их в UITableView. Каждая ячейка имеет изображение, и это изображение соответствует User.profilePicture.
После инициализации я не загружаю изображение профиля с сервера, я загружаю его только тогда, когда оно проходит мимо этой ячейки (ленивая загрузка). После загрузки я сохраняю загруженный образ в соответствующий файл User.profilePicture в стеке данных ядра.
Есть ли способ для controllerDidChangeContent вызываться при обновлении сущности пользователя?? Мое текущее понимание состоит в том, что мой NSFetchedResultsController может следовать только за сущностью Post, так как это то, что я изначально установил для него, и не может отслеживать и отслеживать обновления через отношения, это правда?
2 ответа
К сожалению, я знаю только о Гадком решении этой проблемы.
В вашем 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;
}
Я думаю, что эта проблема может быть решена без участия NSFetchedResultsController.
используйте SDWebImage, SDWebImage может загружать изображения с удаленного сервера асинхронно, просто сделайте это:
[myImageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
используйте KVO, добавьте наблюдателя в сущность пользователя и обновите соответствующий вид изображения соответствующим образом. Но код для KVO довольно сложный, ReactiveCocoa может упростить их:
[RACAble(user.profilePicture) subscribeNext:^(UIImage *image) { [myImageView setImage:image]; }];