当我的用户看到一张图片时,她可以通过按下按钮来点赞。运行以下代码:
- (void)feedback:(Item *)item isLiked:(bool)liked {
// Update the item with the new score asynchornously
NSManagedObjectID *itemId = item.objectID;
dispatch_async(dispatch_get_main_queue(), ^{
// Create a new managed object context and set its persistent store coordinator
// Note that this **must** be done here because this context belongs to another thread
AppDelegate *theDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *localContext = [[NSManagedObjectContext alloc] init];
[localContext setPersistentStoreCoordinator:[theDelegate persistentStoreCoordinator]];
Item *localItem = (Item *)[localContext objectWithID:itemId];
localItem.liked = [NSNumber numberWithBool:liked];
localItem.updated_at = [NSDate date];
NSError *error;
if (![localContext save:&error]) {
NSLog(@"Error saving: %@", [error localizedDescription]);
}
});
在我的应用程序中, LikedViewController 显示用户喜欢的图像。LikedVC 由一个连接到 NSFetchedResultsController 的 UITableViewController 组成。
喜欢VC:
- (void)viewDidLoad
{
[super viewDidLoad];
// NSFetchedResultsController
NSManagedObjectContext *moc = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
_fetchedResultsController = \
[[NSFetchedResultsController alloc] initWithFetchRequest:[self.delegate getFetchRequest]
managedObjectContext:moc
sectionNameKeyPath:nil
cacheName:nil]; // TODO investigate whether we should bother with cache
_fetchedResultsController.delegate = self;
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
// Update to handle the error appropriately.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
exit(-1); // Fail
}
// Bottom loading bar
self.tableView.tableFooterView = self.footerView;
self.footerActivityIndicator.hidesWhenStopped = true;
// ActivityIndicator
self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
self.activityIndicator.color = [UIColor blackColor];
[self.tableView addSubview:self.activityIndicator];
self.activityIndicator.hidesWhenStopped = true;
// FIXME Unable to center it inside the tableView properly
self.activityIndicator.center = CGPointMake(self.tableView.center.x, self.tableView.center.y - self.tabBarController.tabBar.frame.size.height);
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// Automatically fetch when there is nothing in the UITableView
if ([self tableView:self.tableView numberOfRowsInSection:0] == 0) {
if ([self canFetch]) {
[self refill];
}
}
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
if (self.operation && self.operation.isExecuting) {
NSLog(@"Cancelling Operation: %@", self.operation);
[self.operation cancel];
self.isFetching = false;
}
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"FeedCell";
Item *item = [_fetchedResultsController objectAtIndexPath:indexPath];
FeedCell *cell = (FeedCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.item = item;
cell.tag = indexPath.row;
cell.customImageView.userInteractionEnabled = YES;
// NOTE Don't try to do this at the UITableViewCell level since the tap will be eaten by the UITableView/ScrollView
if (self.likeOnTap) {
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
tap.numberOfTapsRequired = 1;
[cell.customImageView addGestureRecognizer:tap];
}
// Set up the buttons
[cell.likeButton addTarget:self action:@selector(liked:) forControlEvents:UIControlEventTouchUpInside];
[cell.dislikeButton addTarget:self action:@selector(disliked:) forControlEvents:UIControlEventTouchUpInside];
[cell.detailButton addTarget:self action:@selector(detailed:) forControlEvents:UIControlEventTouchUpInside];
[[SDImageCache sharedImageCache] queryDiskCacheForKey:item.image_url done:^(UIImage *image, SDImageCacheType type) {
if (image) {
[cell setCustomImage:image];
} else {
// If we have to download, make sure user is on the image for more than 0.25s before we
// try to fetch. This prevents mass downloading when the user is scrolling really fast
double delayInSeconds = 0.25;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
if ([self isIndexPathVisible:indexPath]) {
[SDWebImageDownloader.sharedDownloader
downloadImageWithURL:[NSURL URLWithString:item.image_url]
options:0
progress:^(NSUInteger receivedSize, long long expectedSize) { }
completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
if (image && finished) {
[cell setCustomImage:image];
[[SDImageCache sharedImageCache] storeImage:image forKey:item.image_url];
}
}];
}
});
}
}];
// Check if we are almost at the end of the scroll. If so, start fetching.
// Doing this here is better than overriding scrollViewDidEndDragging
if (indexPath.row >= [self.tableView numberOfRowsInSection:0] - 3) {
[self refill];
}
return cell;
}
#pragma mark - Table view delegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id sectionInfo = [_fetchedResultsController.sections objectAtIndex:section];
NSInteger ret = [sectionInfo numberOfObjects];
self.hasContent = (ret != 0);
return ret;
}
# pragma mark - NSFetchedResultsControllerDelegate
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
NSLog(@"1");
[self.tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
NSLog(@"2");
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
NSLog(@"3");
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[NSException raise:@"Unknown update" format:@"NSFetchedResultsChangeUpdate: invoked"];
// [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[NSException raise:@"Unknown update" format:@"NSFetchedResultsChangeMove: invoked"];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
NSLog(@"4");
[self.tableView endUpdates];
}
(请注意,我省略了一些信息以使这个问题简短)
这是 LikedVC 的 fetchRequest
- (NSFetchRequest *)getFetchRequest {
NSManagedObjectContext *moc = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Item" inManagedObjectContext:moc];
[request setPredicate:[NSPredicate predicateWithFormat:@"liked == %d OR origin == %d", 1, OriginsLike]];
[request setEntity:entity];
[request setResultType:NSManagedObjectResultType];
[request setFetchBatchSize:10];
NSSortDescriptor *d = [[NSSortDescriptor alloc] initWithKey:@"updated_at" ascending:NO selector:nil];
[request setSortDescriptors:[NSArray arrayWithObject:d]];
return request;
}
我看到用户喜欢某个项目的错误,但是当用户切换到 LikedVC 时,该项目不会显示在任何地方。
我在 tableView 的 controllerDidChangeContent、controllerWillChangeContent 等方法中添加了 NSLog(@"1")、NSLog(@"2")、...。我根本没有看到“1”、“2”、.. 被记录。
为什么我的 NSFetchedResultsController 不起作用?