NSFetchedResultsController `performFetch:` 结果不再排序
我使用 NSFetchedResultsController 管理一个表视图,其获取请求对日期属性使用简单的排序。它在第一次加载时正确排序,但当我刷新或调用 loadMore
方法(见下文)时,排序顺序显示为随机。
NSFetchedResultsController 方法
- (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;
}
loadMore 方法
- (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];
});
}
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
从互联网获取数据后调用的方法
- (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];
});
}
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];
});
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先,您尝试在另一个队列上运行获取结果控制器(FRC),这是毫无意义的。不要将从网络下载数据与从本地持久存储文件获取数据混淆。
网络操作可以在后台执行,但与 UI 相关的操作(例如 FRC)需要在前台执行。如果您修改另一个队列中的 FRC,它将与表视图不同步。
其次,您必须删除 FRC 的缓存,并在对获取请求进行任何更改后调用其
performFetch
。。在某些情况下,您可以事后更改fetchLimit
。这可能会产生不可预测的行为(尽管在这种情况下,更改似乎毫无意义,因为它从未被使用过。)我建议从队列中删除 FRC 代码,而只是让它以标准方式响应另一个队列上所做的更改。然后我会清理对获取请求的更改。最后,我将摆脱获取限制。它们很少能大幅提高效率,当你有排序时更是如此。
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 thefetchLimit
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.