UItableView 上的多个 NsfetchedResultsController
我在 tableView
中实现 2 个 nsfetchedresultsController
时遇到困难。我想要在表的每个部分(2 个部分)中都有一个 fetchedresultsController,如下所示:
愿望清单
- 产品
- product2
购买
- 产品3
我知道对于这个例子,我不需要 2 个 nsfetchedResultsController,但稍后我会需要这个..
当我从一个 nsfetchedResultsController 中删除一个产品时,它会传递到另一个,我收到此错误:
无效更新:第 0 节中的行数无效。 更新 (0) 后现有节中包含的行必须是 等于该部分之前包含的行数 update(0),加上或减去插入或删除的行数 该部分(1 插入,0 删除)。与用户信息(空)“
我认为发生这种情况是因为当第一个 fetchedRController 检测到更改时,它会在调用第二个之前更新 tableView 是这样吗?我应该使用 NSMutableArrays 并手动更新 tableView 吗?
代码:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger numberOfRows = 0;
switch (section)
{
case WISHLIST_SECTION:
{
numberOfRows =[[fetchedResultsControllerwish fetchedObjects]count];
};
break;
case PURCHASED_SECTION:
{
numberOfRows =[[fetchedResultsControllerPurchased fetchedObjects]count];
};
break;
default:
break;
}
return numberOfRows;
}
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
// The fetch controller is about to start sending change notifications, so prepare the table view for updates.
[self.tableView beginUpdates];
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
// The fetch controller has sent all current change notifications, so tell the table view to process all updates.
[self.tableView endUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableViewT = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableViewT insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableViewT deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:(GiftEventTableViewCell *)[tableViewT cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableViewT deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[tableViewT insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
-(void)configureCell:(GiftEventTableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.section) {
case WISHLIST_SECTION:
{
GiftEvent *giftEv=(GiftEvent *)[fetchedResultsControllerwish objectAtIndexPath:indexPath];
cell.gift=giftEv;
};
break;
case PURCHASED_SECTION:
{
GiftEvent *giftEv=(GiftEvent *)[fetchedResultsControllerPurchased objectAtIndexPath:indexPath];
//if i don't use indexpath.row in the second section i get an out of bounds error
//GiftEvent *giftEv=(GiftEvent *)[[fetchedResultsControllerPurchased fetchedObjects]objectAtIndex: indexPath.row];
cell.gift=giftEv;
};
break;
default:
break;
}
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete)
{
switch (indexPath.section) {
case WISHLIST_SECTION:
{
// Delete the managed object for the given index path
[self.managedObjectContext deleteObject:[fetchedResultsControllerwish objectAtIndexPath:indexPath]];
// Save the context.
NSError *error;
if (![self.managedObjectContext save:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
[self.tableView reloadData];
};
break;
case PURCHASED_SECTION:
{
// Delete the managed object for the given index path
[self.managedObjectContext deleteObject:[fetchedResultsControllerPurchased objectAtIndexPath:indexPath]];
// Save the context.
NSError *error;
if (![self.managedObjectContext save:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
};
break;
default:
break;
}
}
}
I'm having difficulty implementing 2 nsfetchedresultsController
in a tableView
. I wanted a fetchedresultsController in each section of the table (2 sections), something like this:
Wishlist
- product
- product2
Bought
- product3
I know that for this example i wouldn't need 2 nsfetchedResultsController but i will need this later..
when i remove a product from one nsfetchedResultsController it passes to the other and i get this error:
Invalid update: invalid number of rows in section 0. 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 (0), plus or minus the number of rows inserted or deleted from
that section (1 inserted, 0 deleted). with userInfo (null)"
I thinks this happens because when the first fetchedRController detects a change it updates the tableView before the second one is called is that right ? should i use NSMutableArrays and update the tableView manually?
The code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger numberOfRows = 0;
switch (section)
{
case WISHLIST_SECTION:
{
numberOfRows =[[fetchedResultsControllerwish fetchedObjects]count];
};
break;
case PURCHASED_SECTION:
{
numberOfRows =[[fetchedResultsControllerPurchased fetchedObjects]count];
};
break;
default:
break;
}
return numberOfRows;
}
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
// The fetch controller is about to start sending change notifications, so prepare the table view for updates.
[self.tableView beginUpdates];
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
// The fetch controller has sent all current change notifications, so tell the table view to process all updates.
[self.tableView endUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableViewT = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableViewT insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableViewT deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:(GiftEventTableViewCell *)[tableViewT cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableViewT deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[tableViewT insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
-(void)configureCell:(GiftEventTableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.section) {
case WISHLIST_SECTION:
{
GiftEvent *giftEv=(GiftEvent *)[fetchedResultsControllerwish objectAtIndexPath:indexPath];
cell.gift=giftEv;
};
break;
case PURCHASED_SECTION:
{
GiftEvent *giftEv=(GiftEvent *)[fetchedResultsControllerPurchased objectAtIndexPath:indexPath];
//if i don't use indexpath.row in the second section i get an out of bounds error
//GiftEvent *giftEv=(GiftEvent *)[[fetchedResultsControllerPurchased fetchedObjects]objectAtIndex: indexPath.row];
cell.gift=giftEv;
};
break;
default:
break;
}
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete)
{
switch (indexPath.section) {
case WISHLIST_SECTION:
{
// Delete the managed object for the given index path
[self.managedObjectContext deleteObject:[fetchedResultsControllerwish objectAtIndexPath:indexPath]];
// Save the context.
NSError *error;
if (![self.managedObjectContext save:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
[self.tableView reloadData];
};
break;
case PURCHASED_SECTION:
{
// Delete the managed object for the given index path
[self.managedObjectContext deleteObject:[fetchedResultsControllerPurchased objectAtIndexPath:indexPath]];
// Save the context.
NSError *error;
if (![self.managedObjectContext save:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
};
break;
default:
break;
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
查看 Stack Overflow 上的另一个问题:
Core Data: UITableView with multiple NSFetchedResultControllers
核心数据:具有多个 NSFetchedResultController 的 UITableView
Check out this other question on Stack Overflow:
Core Data: UITableView with multiple NSFetchedResultControllers
Core Data: UITableView with multiple NSFetchedResultControllers
使用多个是错误的方法。正确的解决方案是使用
NSFetchedResultController
的sectionNameKeyPath
参数将结果分组为多个部分,在您的情况下,它将是产品上购买的布尔属性。而且您还应该将其作为升序排列的第一个排序描述符,因为您希望未购买的商品高于已购买的商品。使用标头标题表委托方法为每个部分索引返回字符串“Wishlist”和“Purchased”。如果您认为将来可能有第三个列表,那么您最好使用数字状态属性,并在代码中为产品可能所处的每个状态(或列表)使用枚举。这通常是完成此操作的方式而不是对布尔值进行排序。
Using multiple is the wrong approach. The correct solution is to use the
sectionNameKeyPath
param to theNSFetchedResultController
to group the results into multiple sections, in your case it would be a purchased boolean property on the product. And you should also make this the first sort descriptor in ascending order since you want un-purchased above purchased. Use the header title table delegate method to return the strings "Wishlist" and "Purchased" for each section index.If you think you might have a 3rd list in the future, then you would better using a numeric status property, and in code an enum for each of the states (or lists) the product can be in. That's usually how this is done rather than sorting on a bool.
我刚刚创建了一个 pod 来解决这个问题。 https://github.com/imton/GMCoreDataMultipleSectionsTableVC
你可以看看并告诉我你的想法,欢迎反馈!
G
I just created a pod to solve this. https://github.com/imton/GMCoreDataMultipleSectionsTableVC
You can check it out and tell me what you think, feedback welcome!
G
抱歉各位,这是一个菜鸟错误。发生错误是因为indexPath.section返回了tableView中的部分,但我在fetchedResultsController中没有部分(始终索引0)。
编辑:实际上有一个..
不确定这是否是最好的方法,但解决了问题。
Sorry guys, it was a noob error. The error was happening because the indexPath.section returned the section in the tableView but I had no sections in the fetchedResultsController (always index 0).
EDIT: actually there is one..
Not sure if it's the best way but solved the problem.