开发者

NSFetchedResultsController `performFetch:` Results No Longer Sorted

I managed a tableview with NSFetchedResultsController whose fetch request uses a simple sort on a date attribute. It sorts properly when it first loads but when I refresh or call the loadMore method (see below) the sort order appears random.

The NSFetchedResultsController method

- (NSFetchedResultsController *)getFetchedResultsController {
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }
    [NSFetchedResultsController deleteCacheWithName:@"LatestNews"];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:[NSEntityDescription entityForName:@"News" inManagedObjectContext:self.managedObjectContext]];
    [request setFetchLimit:kDefaultNewsLimit];
    [request setFetchBatchSize:20];
    [request setIncludesPropertyValues:NO];
    NSSortDescriptor *dateSortor = [NSSortDescriptor sortDescriptorWithKey:@"dateAdded" ascending:NO];
    [request setSortDescriptors:[NSArray arrayWithObject:dateSortor]];

    _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@"LatestNews"];
    _fetchedResultsController.delegate = self;

    return _fetchedResultsController;
}

The loadMore method

- (void)loadMore {
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    UIActivityIndicatorView *loadingIndicator = (UIActivityIndicatorView *)[loadMoreButton viewWithTag:3];
    [loadingIndicator startAnimating];
    NSUInteger newsLoaded = self.numberOfLimitedNews;

    double delayInSeconds = 1.0;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        //fetch news from internet with date args
        NSDate *lastNewsDate;
        NSDate *beginTime, *endTime;
        NSDictionary *condition;


        [self.fetchedResultsController.fetchRequest setFetchLimit:self.numberOfLimitedNews+kDefaultNewsLimit];
        [NSFetchedResultsController deleteCacheWithName:@"LatestNews"];
        [self.fetchedResultsController performFetch:nil];
        if (self.numberOfLimitedNews - newsLoaded < kDefaultNewsLimit) {

            News *lastNews = [newsHelper getLastNews:@"LatestNews" idValue:nil];
            lastNewsDate = lastNews.dateAdded;
            beginTime = [NSDate dateWithTimeIntervalSince1970:0];
            if (!lastNewsDate) {
                endTime = [NSDate date];
            }
            else {
                endTime = lastNewsDate;
            }
            condition = [NSDictionary dictionaryWithObjectsAndKeys:beginTime, @"beginTime", endTime, @"endTime", nil];
            NSUInteger newsToFetch = kDefaultNewsLimit - self.numberOfLimitedNews % kDefaultNewsLimit;

            [newsHelper getNumberOfNews:newsToFetch forLanguages:@"en" withCondition:condition];
            [self.fetchedResultsController.fetchRequest setFetchLimit:self.fetchedResultsController.fetchRequest.fetchLimit+newsToFetch];
        }

        [self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];
    });
}

The Results:

2011-09-13 16:48:20.959 HJNews[5971:bc03] 2011-02-04 06:00:00 +0000
2011-09-13 16:48:21.079 HJNews[5971:bc03] 2011-09-13 08:29:48 +0000
2011-09-13 16:48:21.230 HJNews[5971:bc03] 2011-02-19 01:30:00 +0000
2011-09-13 16:48:21.463 HJNews[5971:bc03] 2011-09-13 08:45:00 +0000
2011-09-13 16:48:21.879 HJNews[5971:bc03] 2011-03-06 02:00:00 +0000
2011-09-13 16:48:22.143 HJNews[5971:bc03] 2010-12-01 02:40:00 +0000
2011-09-13 16:48:22.229 HJNews[5971:bc03] 2011-09-13 02:03:43 +0000
2011-09-13 16:48:22.313 HJNews[5971:bc03] 2011-09-13 08:10:33 +0000
2011-09-13 16:48:22.446 HJNews[5971:bc03] 2011-01-02 06:00:00 +0000
2011-09-13 16:48:22.627 HJNews[5971:bc03] 2011-09-13 08:45:00 +0000
2011-09-13 16:48:22.978 HJNews[5971:bc03] 2011-01-23 02:00:01 +0000
2011开发者_开发知识库-09-13 16:48:23.092 HJNews[5971:bc03] 2011-09-13 03:35:40 +0000
2011-09-13 16:48:23.196 HJNews[5971:bc03] 2011-02-18 06:20:00 +0000
2011-09-13 16:48:23.346 HJNews[5971:bc03] 2011-09-13 00:00:00 +0000
2011-09-13 16:48:23.812 HJNews[5971:bc03] 2011-02-08 06:00:00 +0000
2011-09-13 16:48:23.980 HJNews[5971:bc03] 2011-09-12 01:40:10 +0000
2011-09-13 16:48:24.179 HJNews[5971:bc03] 2011-01-18 06:00:00 +0000
2011-09-13 16:48:26.257 HJNews[5971:bc03] 2010-12-22 06:30:00 +0000
2011-09-13 16:48:27.783 HJNews[5971:bc03] 2011-02-08 06:00:00 +0000
2011-09-13 16:48:27.784 HJNews[5971:bc03] 2011-09-12 01:40:10 +0000
2011-09-13 16:48:27.785 HJNews[5971:bc03] 2011-01-18 06:00:00 +0000
2011-09-13 16:48:27.785 HJNews[5971:bc03] 2010-12-22 06:30:00 +0000
2011-09-13 16:48:27.786 HJNews[5971:bc03] 2011-09-13 02:10:17 +0000

The method called after data fetched from internet

- (void)asiRequestFinished:(NSNotification *)notification {
    dispatch_async(dispatch_get_main_queue(), ^{
        [NSFetchedResultsController deleteCacheWithName:@"LatestNews"];
        [self.fetchedResultsController performFetch:nil];
        [self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];
        UIActivityIndicatorView *loadingIndicator = (UIActivityIndicatorView *)[loadMoreButton viewWithTag:3];
        [loadingIndicator stopAnimating];
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        isRefreshing = NO;
        [refreshView egoRefreshScrollViewDataSourceDidFinishedLoading:self.tableView];
    });
}


Firstly, you are trying to run the fetch results controller (FRC) on another queue which is rather pointless. Don't confuse downloading data from the network with fetching data from the local persistent store file.

Network actions can be performed in the background but UI related actions like the FRC need to be in the foreground. If you modify the FRC in another queue, it will come out of sync with the tableview.

Secondly, you have to delete the FRC's cache and call its performFetch after you make any changes to the fetch request. You change the fetchLimit afterwards in some cases. That can produce unpredictable behavior (although in this case the change seems pointless as it is never used.)

I would suggest removing the FRC code from the queue and instead simply have it respond to changes made on another queue in the standard manner. Then I would clean up the changes to the fetch request. Lastly, I would get rid of the fetch limits. They seldom improve efficiency much and even less so when you have sorts.


It seems resolved. I saved data to the Core Data when the app entered to background before. Now I Save it after data downloaded from internet.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜