【问题标题】:Dynamically setting fetchLimit for NSFetchedResultsController为 NSFetchedResultsController 动态设置 fetchLimit
【发布时间】:2011-07-20 01:51:41
【问题描述】:

我正在使用 NSFetchedResultsController 将数据填充到 UITableView。 这是一个简单的聊天应用程序,我想先将最新的 25 条消息加载到表格中,然后在用户向上滚动查看旧消息时加载更多消息(聊天消息按升序排列)。

我为 willDisplayCell 中的 NSFetchedResultsController 调用了一个 setFetchLimit: 方法:就像这样......

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if(indexPath.row == 0)
    {
        [self performSelector:@selector(getMoreMessages) withObject:nil afterDelay:1.0];
    }
}

当 UITableView 的第一行已经显示时,getMoreMessages 会尝试重置 fetchLimit 重新加载 UITableView 像这样.....

- (void)getMoreMessages
{
    maxListItems += 25;
    NSLog(@"set maxListItems: %d", maxListItems);
    [self.resultsController.fetchRequest setFetchLimit:maxListItems];
    [self._tableView reloadData];
}

但是,它似乎不起作用,表格数据不会改变。 最初的 NSFetchRequest 是这样设置的...

NSFetchRequest *chatDataRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"ChatData" inManagedObjectContext:appDelegate.managedObjectContext];
[chatDataRequest setEntity:entity];

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(key != 0 OR messageNo != 0) and matchNo = %d", matchNo];
[chatDataRequest setPredicate:predicate];

NSSortDescriptor *sortDescripter1 = [[NSSortDescriptor alloc] initWithKey:@"status" ascending:YES];
NSSortDescriptor *sortDescripter2 = [[NSSortDescriptor alloc] initWithKey:@"messageNo" ascending:YES];
NSArray *sortDescripters = [[NSArray alloc] initWithObjects:sortDescripter1, sortDescripter2, nil];
[chatDataRequest setSortDescriptors:sortDescripters];
[sortDescripters release];
[sortDescripter1 release];
[sortDescripter2 release];

[chatDataRequest setFetchLimit:25];

NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:chatDataRequest managedObjectContext:appDelegate.managedObjectContext sectionNameKeyPath:nil cacheName:[NSString stringWithFormat:@"%d_chat.cache", matchNumber]];
[chatDataRequest release];
fetchedResultsController.delegate = self;
NSError *error;
BOOL success = [fetchedResultsController performFetch:&error];
if(!success) NSLog(@"error: %@", error);
self.resultsController = fetchedResultsController;

回到问题。

如何动态更改 NSFetchedResultsController 的 fetchLimit?

任何点击都会很棒! 谢谢!

【问题讨论】:

    标签: iphone objective-c ios


    【解决方案1】:

    使用setFetchLimit,使用setBatchSize,详细答案见下文。

    fetchedObjects 数组的计数可能不是您想要的,因为它不会更新持久存储中的更改。来自 NSFetchedResultsController 文档:

    结果数组仅包含由获取请求 (fetchRequest) 指定且与其谓词匹配的实体的实例。 (如果获取请求没有谓词,则结果数组包括获取请求指定的实体的所有实例。)

    结果数组反映了控制器托管对象上下文中托管对象的内存状态,而不是它们在持久存储中的状态。但是,返回的数组不会随着托管对象的插入、修改或删除而更新。

    如果您只想获取 20 个对象,请设置 NSFetchRequest 的获取限制。如果只想在内存中保留 20 个对象,请使用 NSFetchRequest 对象的 setBatchSize。

    【讨论】:

      【解决方案2】:

      想出了这个。 看起来我必须运行 performFetch: 在我更改 fetchLimit 之后。 :D

      [self.resultsController.fetchRequest setFetchLimit:maxListItems];
      [self.resultsController performFetch:&error];
      

      【讨论】:

      • 另外,请确保重新加载 UITableView 后记
      • 它是否与 uifetchedresultscontrollerdelegate controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: 一起工作?不适合我=(
      • 您需要在执行此操作之前调用 [NSFetchedResultsController deleteCacheWithName:@"cacheName"],如 Apple Documentation of NSFetchedResultsController.fetchRequest 所述:“初始化后不得更改它、它的谓词或排序描述符无需禁用缓存或调用 +deleteCacheWithName"
      • 执行此操作并重新加载 tableView 将跳转到您刚刚加载的消息的顶部,我认为这是不可取的。您希望为用户提供流畅的滚动体验。如果您没有临时 sectionNameKeyPath 并且您正在使用 AutoDimensions,则按照下面的建议使用 setBatchSize。但是,如果您没有使用 AutoDimension 或者您使用的是瞬态属性,那么 setBatchSize 将不起作用。在这种情况下,您最好不要使用 fetchedResultsController,而只是加载更多消息以添加到您的数组中,而不是像原来一样再次加载所有消息。
      猜你喜欢
      • 2011-06-18
      • 2012-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-07
      • 1970-01-01
      • 2018-02-07
      • 1970-01-01
      相关资源
      最近更新 更多