【问题标题】:Core Data NSFetchedResultsController and batch size set loads all rows核心数据 NSFetchedResultsController 和批量大小集加载所有行
【发布时间】:2015-10-20 16:16:31
【问题描述】:

我的核心数据数据库中有数千个点,我希望将它们全部放在我的 tableView 中,但我不想一次将它们全部提取到内存中,但我想使用 NSFetchedResultsController 并将它们批处理有一些常数。我像在许多教程中看到的那样设置它,并设置了 fetchBatchSize 属性,但是在显示之前加载视图控制器需要几秒钟。

这个函数在viewDidLoad中被调用:

- (void)initPositionsFetch {
    // Initialize Fetch Request
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"OpenPositionCD"];

    // Add Sort Descriptors
    [fetchRequest setSortDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"timestamp" ascending:NO]]];

    // Add predicate
    [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"moduleId == %@", _module.moduleId]];

    [fetchRequest setFetchBatchSize:100];

    [fetchRequest setIncludesPendingChanges:NO];

    // Initialize Fetched Results Controller
    self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:temporaryContext sectionNameKeyPath:nil cacheName:nil];

    // Configure Fetched Results Controller
    [self.fetchedResultsController setDelegate:self];

    // Perform Fetch
    NSError *error = nil;
    [self.fetchedResultsController performFetch:&error];

    if (error) {
        NSLog(@"Unable to perform fetch.");
        NSLog(@"%@, %@", error, error.localizedDescription);
    }
}

NSFetchedResultsControllerDelegate 方法:

#pragma mark - NSFetchedResultsControllerDelegate
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView beginUpdates];
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView endUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
    switch (type) {
        case NSFetchedResultsChangeInsert: {
            [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
        }
        case NSFetchedResultsChangeDelete: {
            [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
        }
        case NSFetchedResultsChangeUpdate: {
            [self configureCell:(PanelPositionCell *)[self.tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;
        }
        case NSFetchedResultsChangeMove: {
            [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
        }
    }
}

UITableView 委托方法:

#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    if (_tracksVisible)
        return 1;
    else
        return [[self.fetchedResultsController sections] count];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (_tracksVisible)
        return [_tracks count];
    else {
        NSArray *sections = [self.fetchedResultsController sections];
        id<NSFetchedResultsSectionInfo> sectionInfo = [sections objectAtIndex:section];

        return [sectionInfo numberOfObjects];
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier;
    if(_tracksVisible)
        CellIdentifier = TrackCellIdentifier;
    else
        CellIdentifier = PositionCellIdentifier;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    if(_tracksVisible) {
        [((PanelTrackCell *)cell) setValuesByTrackCD:[_tracks objectAtIndex:indexPath.row]];
    } else  {
        [self configureCell:(PanelPositionCell *)cell atIndexPath:indexPath];
    }

    return cell;
}

- (void)configureCell:(PanelPositionCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    // Fetch Record
    NSManagedObject *record = [self.fetchedResultsController objectAtIndexPath:indexPath];
    OpenPositionCD *position = (OpenPositionCD *)record;

    // Update Cell
    [cell setValuesByOpenPositionCD:position];
}

这有什么问题?为什么它加载所有行?核心数据模型可能有问题吗?我试图删除谓词,但没有帮助。 SortDescriptor 必须设置,但这是我想到的唯一可能有问题的地方。我希望结果按时间戳排序。 Timestamp 是 Date 属性,设置为 Indexed。当我首先必须得到它然后我可以按时间对它们进行排序时,如何对结果进行批处理?我使用tableView通过switch(_tracksVisible)显示另一个数据应该没有问题,对吧?

我什至尝试使用此代码在后台获取结果:

[[[self fetchedResultsController] managedObjectContext] performBlock:^{
        NSError *error = nil;
    [self.fetchedResultsController performFetch:&error];

    if (error) {
        NSLog(@"Unable to perform fetch.");
        NSLog(@"%@, %@", error, error.localizedDescription);
    }
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            [_tableView reloadData];
        }];
}];

发生的情况是控制器显示得更早,但随后 UI 冻结,所需时间几乎与以前相同。

【问题讨论】:

    标签: ios objective-c uitableview core-data nsfetchedresultscontroller


    【解决方案1】:

    看起来您可能正在使用在它和持久存储协调器之间有另一个上下文的上下文。我在搜索相同问题时发现了这篇文章:我的批量大小被我的获取请求忽略了,因为我使用的是嵌套上下文。在此处查看更多信息,并点击相关 SO 帖子的链接并打开雷达错误报告:https://github.com/Simperium/simperium-ios/issues/425。 Core Data 已经存在了这么长时间,而且看起来很普遍,因为这仍然是一个问题,这真是太糟糕了。无论如何,可能会很好地在其上提交雷达。即使他们将其作为副本关闭,也许他们会发现这是许多人遇到的问题。

    【讨论】:

      【解决方案2】:

      尝试在 BatchSize 中使用较低的值,可能是 20

      [fetchRequest setFetchBatchSize:20];

      你也可以尝试添加 initPositionFetch

      [fetchRequest setFetchLimit:20];

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-02
        相关资源
        最近更新 更多