gpt4 book ai didi

ios - 如何正确处理 UITableView 中的可折叠部分更新(调用 -controllerDidChangeContent 期间的严重应用程序更新)

转载 作者:行者123 更新时间:2023-11-28 18:33:39 24 4
gpt4 key购买 nike

我正在开发一个涉及可折叠部分的核心数据应用程序。

基本上,如果我跨部分移动托管对象,或者只是在其部分打开时将其删除,我会收到以下错误:

2014-04-28 19:38:44.690 uRSS[663:60b] CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. Invalid update: invalid number of rows in section 7. The number of rows contained in an existing section after the update (2) must be equal to the number of rows contained in that section before the update (3), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out). with userInfo (null)

我相信它是关于我在 didChange Object 方法中处理更改的方式,但我被 ATM 卡住了:

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
{
UITableView *tableView = self.tableView;

switch(type) {
case NSFetchedResultsChangeInsert:
NSLog(@"MasterViewController::didChangeObject **** Inserting something in %@**** ", _detailViewController.detailItem.category.name);
if ([_detailViewController.detailItem.category.open boolValue]) {
[tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
}
break;

case NSFetchedResultsChangeDelete:
NSLog(@"MasterViewController::didChangeObject **** Deleting something in %@**** ", _detailViewController.detailCategory.name);

if ([_detailViewController.detailCategory.open boolValue]) {
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
break;

case NSFetchedResultsChangeUpdate:
NSLog(@"MasterViewController::didChangeObject **** Changing something in %@**** ", _detailViewController.detailCategory.name);

if ([_detailViewController.detailCategory.open boolValue]) {
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
}
break;

case NSFetchedResultsChangeMove:
NSLog(@"MasterViewController::didChangeObject **** Moving something from %@ to %@**** ", _detailViewController.detailCategory.name, _detailViewController.detailItem.category.name);

if ([_detailViewController.detailCategory.open boolValue]) {
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
if ([_detailViewController.detailItem.category.open boolValue]) {
[tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
}
break;
}
}

我的 detailView 附加了 2 个对象:detailItem,一个 feed 和 detailCategory,原始的类别,如果它改变的话。

Category 有一个name 和一个open 属性。如果 open 为 false,则折叠类别(部分)。

到目前为止,我无法在不发生崩溃的情况下删除对象或更改它们的类别。如果类别已关闭,我可以删除它们。

每当创建一个新对象(它有自己的"new"类别)时,它就会错误地出现在当前打开的类别中。如果没有类别被打开,那么它会期望用新对象创建新类别。

有人可以告诉我如何处理这个吗?

更新(1):这是 UIDataSource 的更多信息:

这是在我的 detailView 中跨 类别 移动 Feed 的时间和方式:

-(void) updateCategory:(id)sender
{
if (!_categoriesPopover) {
return;
}
[_categoriesPopover dismissPopoverAnimated:YES];
[_mainMOC performBlockAndWait:^{
Category *category=_categoryView.categoryChosen;
if (!category) {
return;
}

self.detailItem.category.open=[NSNumber numberWithBool:NO];

self.detailCategory = self.detailItem.category;
self.detailItem.category=category;

self.detailItem.category.open=[NSNumber numberWithBool:YES];

NSError *error;
if (![_mainMOC save:&error])
{
NSLog(@"DetailViewController::updateCategory Error saving context: %@", error);
} else {
[[NSNotificationCenter defaultCenter] postNotificationName:@"feedUpdatedInDetailView" object:nil];
}
}];
}

一旦我点击了这个屏幕截图中选择的目的地 Category 就会发生这种情况: My RSS Reader Interface during the Category switch operation. Change Category is the folder item in the bottom menu bar of the detail View

更新(2):

这是 numberOfRowsInSection 方法:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [_filteredCategoryArray count];
} else {
if ([[[self.fetchedResultsController sections][section] objects] count]>0) {
Category *cat = ((Feed *)[[[self.fetchedResultsController sections][section] objects] objectAtIndex:0]).category;
return [cat.open boolValue] ? [[self.fetchedResultsController sections][section] numberOfObjects] : 0;
} else {
return 0;
}
}
}

更新(3):

我 NSLogged 一些变量以查看发生了什么,我认为我们可以忘记这里的打开/关闭方面。

a) 下面是 DetailView 中发生的事情:

-(void) updateCategory:(id)sender
{
if (!_categoriesPopover) {
return;
}
[_categoriesPopover dismissPopoverAnimated:YES];
Category *category=_categoryView.categoryChosen;
if (!category) {
return;
}

[_mainMOC performBlockAndWait:^{
NSLog(@"BEFORE: oldcat: %@ (%d) / newcat: %@ (%d)", _detailItem.category.name, [_detailItem.category.feeds count], category.name, [category.feeds count]);
self.detailItem.category.open=[NSNumber numberWithBool:NO];

self.detailCategory = self.detailItem.category;
self.detailItem.category=category;

self.detailItem.category.open=[NSNumber numberWithBool:YES];

NSError *error;
if (![_mainMOC save:&error])
{
NSLog(@"DetailViewController::updateCategory Error saving context: %@", error);
} else {
[[NSNotificationCenter defaultCenter] postNotificationName:@"feedUpdatedInDetailView" object:nil];
}
NSLog(@"AFTER: oldcat: %@ (%d) / newcat: %@ (%d)", _detailCategory.name, [_detailCategory.feeds count], _detailItem.category.name, [_detailItem.category.feeds count]);
}];
}

b) 这是 MasterView 中的内容:

            case NSFetchedResultsChangeMove:
NSLog(@"MVC: oldcat: %@ (%d) / newcat: %@ (%d)", _detailViewController.detailCategory.name, [_detailViewController.detailCategory.feeds count], _detailViewController.detailItem.category.name, [_detailViewController.detailItem.category.feeds count]);

NSLog(@"MasterViewController::didChangeObject **** Moving something from %@ to %@**** ", _detailViewController.detailCategory.name, _detailViewController.detailItem.category.name);

[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;

c) 以下是日志内容:

2014-04-30 18:52:04.771 uRSS[465:60b] BEFORE: oldcat: trucs (2) / newcat: Misc (7)
2014-04-30 18:52:04.771 uRSS[465:60b] MVC: oldcat: trucs (1) / newcat: Misc (8)
2014-04-30 18:52:04.772 uRSS[465:60b] MasterViewController::didChangeObject **** Moving something from trucs to Misc****
2014-04-30 18:52:04.772 uRSS[465:60b] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2935.137/UITableView.m:1368
2014-04-30 18:52:04.772 uRSS[465:60b] CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. Invalid update: invalid number of rows in section 5. The number of rows contained in an existing section after the update (8) must be equal to the number of rows contained in that section before the update (0), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out). with userInfo (null)
2014-04-30 18:52:04.773 uRSS[465:60b] [AppDelegate::saveContextChanges] merged.
2014-04-30 18:52:04.774 uRSS[465:8c03] [AppDelegate::saveContextChanges] merged.
2014-04-30 18:52:04.775 uRSS[465:60b] AFTER: oldcat: trucs (1) / newcat: Misc (8)

我不明白的是,DVC 在 PerformBlockAndWait 循环中工作,但在新值似乎提交到 DVC 之前,MVC 被调用了新值。这怎么可能?

怎么了???

更新(4):我按照马库斯的建议做了,并删除了 MOC 保存。日志看起来更好(之前和之后发生在 DVC 中,MVC 预期发生在 MVC 之后并且值是正确的):

2014-05-01 07:27:39.391 uRSS[742:60b] BEFORE: oldcat: Misc (8) / newcat: trucs (1)
2014-05-01 07:27:39.392 uRSS[742:60b] AFTER: oldcat: Misc (7) / newcat: trucs (2)
2014-05-01 07:27:39.400 uRSS[742:60b] MVC: oldcat: Misc (7) / newcat: trucs (2)

但是:我仍然收到错误:

2014-05-01 07:27:39.400 uRSS[742:60b] MasterViewController::didChangeObject **** Moving something from Misc to trucs**** 
2014-05-01 07:27:39.401 uRSS[742:60b] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2935.137/UITableView.m:1368
2014-05-01 07:27:39.401 uRSS[742:60b] CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. Invalid update: invalid number of rows in section 5. The number of rows contained in an existing section after the update (0) must be equal to the number of rows contained in that section before the update (8), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out). with userInfo (null)

我还看到在重新启动应用程序时,Feed 没有被移动,这通常发生在保存...

UPDATE(5): 我恢复到原来的 didChangeObject 方法并且它有效(即跨类别移动 Feed)。如何在处理过程中保存以“阻止”主 UI? performBlockAndWait显然是不够的。

最佳答案

NSFetchedResultsController 的委托(delegate)方法告诉 UITableView 的内容与 UITableViewDataSource 的方法告诉 TableView 的内容不匹配.

我建议查看您的 UITableViewDataSource 方法,使用调试器并确保它们报告的行数与您的 NSFetchedResultsControllerDelegate 方法相同。

这就是这个错误的根源。

更新

-controller: didChangeObject: atIndexPath: forChangeType: newIndexPath:UITableViewDataSource 中的方法之一之间存在断开连接。根据错误,我猜测它在 -tableView: numberOfRowsInSection: 中,这是我希望您添加到问题中的方法。

NSFetchedResultsControllerDelegate 完成后,它将对从 UITableViewDataSource 协议(protocol)实现的方法执行 ping 操作,并询问表格的外观。这些答案必须匹配。如果他们不这样做,您将收到此错误。

如果您在调试器中运行它并在这些方法中放置断点并在纸上进行操作,您通常可以找到断开连接的位置。

更新

看起来您正在 Core Data 中存储类别打开状态,然后根据类别是否打开来响应行数。希望我没看错。

如果是这种情况,那么我会建议关闭 并查看崩溃是否消失。这会将您的注意力集中在该逻辑上。您的状态很可能不同步。

关于ios - 如何正确处理 UITableView 中的可折叠部分更新(调用 -controllerDidChangeContent 期间的严重应用程序更新),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23348112/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com