UICollectionview 在使用 Core Data 保存实体后重新加载数据

Posted

技术标签:

【中文标题】UICollectionview 在使用 Core Data 保存实体后重新加载数据【英文标题】:UICollectionview reload data after saving entity with Core Data 【发布时间】:2013-08-04 09:41:52 【问题描述】:

我有一个带有 UICollectionView 的应用程序,视图显示自定义 UICollectionViewCells。当其中一个单元格注册一个水龙头时,它会以模型视图控制器的形式打开一个详细视图。集合视图中填充了来自 Core Data 的数据,如下所示:

#pragma mark - Get Items From CoreData
-(NSArray*)refreshTableData




NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Produkt"
                                          inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSError* error;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];

/*for (Produkt *produkt in fetchedObjects)

    NSLog(@"Name: %@", produkt.name);
*/

return fetchedObjects;


 #pragma mark - UICollectionView Datasource
- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:   (NSInteger)section 
return [[self refreshTableData] count];


 - (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath 
CollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ItemCell" forIndexPath:indexPath];

Produkt* produkt = [[self refreshTableData]objectAtIndex:indexPath.row];

[cell.collectionLabel setText:produkt.name];
[cell.collectionImage setImage:[[UIImage alloc]initWithData:produkt.image]];

[cell.layer setCornerRadius:10];
[cell.layer setMasksToBounds:YES];

CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = cell.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor blackColor] CGColor], (id)[[UIColor whiteColor] CGColor], nil];
[cell.layer insertSublayer:gradient atIndex:0];

return cell;


#pragma mark UICollectionViewDelegate
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath


Produkt* produkt = [[self refreshTableData]objectAtIndex:indexPath.row];
produktView = [[ProduktViewController alloc]
               initWithNibName:@"ProduktViewController"
               bundle:nil];



produktView.modalPresentationStyle = UIModalPresentationFormSheet;
produktView.delegate = self;
produktView.produkt = produkt;

[self presentViewController:produktView animated:YES completion:nil];


- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section 
return UIEdgeInsetsMake(50, 20, 50, 20);

当我创建一个新的 Produkt 对象(NSManagedObject)时,保存它并重新加载 UICollectionView 一切正常。这就是创建新 Produkt-Object 的代码:

-(void)selectedItem:(NSString *)selectedItem
 
//Dismiss the popover if it's showing.
if (itemPickerPopover) 
    [itemPickerPopover dismissPopoverAnimated:YES];
    itemPickerPopover = nil;


if([selectedItem isEqualToString:@"Produkt"])

    NSLog(@"SELECTED ITEM:%@",selectedItem);
    produktView = [[ProduktViewController alloc]
                       initWithNibName:@"ProduktViewController"
                       bundle:nil];
    Produkt* newProdukt = [NSEntityDescription
                           insertNewObjectForEntityForName:@"Produkt"
                           inManagedObjectContext:context];

    produktView.modalPresentationStyle = UIModalPresentationFormSheet;
    produktView.delegate = self;
    produktView.context = context;
    produktView.produkt = newProdukt;

    [self presentViewController:produktView animated:YES completion:nil];



现在当我选择一个单元格并弹出详细视图时,我在详细视图中编辑数据,然后保存它,使用此功能(包含在详细视图类中):

   -(void)saveChanges
 
        NSLog(@"SAVE SAVE SAVE SAVE SAVE SAVE SAVE SAVE SAVE SAVE SAVE ");

    produkt.name = name.text;
    produkt.artikelNr = artikelNr.text;
    produkt.gekauftBei = bestelltBei.text;
    produkt.gebrauchsAnweisung = gebrauchsAnleitung.text;

    NSData *savedImageData = UIImagePNGRepresentation(image.image);
    produkt.image = savedImageData;

    NSError *error;
    [context save:&error];

    

当细节控制器关闭时,这个委托函数被调用:

#pragma mark ProduktView delegate
-(void)didDismissPresentedViewController

NSLog(@"DISMISS CONTROLLER");
[produktView dismissViewControllerAnimated:YES completion:nil];

[collectionView reloadData];

现在问题来了:当我保存更改的对象并重新加载表格视图时,显示的单元格关联到错误的实体。例如,集合视图显示对象: 1 、 2 、 3 、 4 但是当我单击对象 3 时,详细视图显示对象 1。在我关闭视图控制器后,集合视图再次更改顺序。当我重新启动应用程序时,我对对象所做的更改不会保存。

在主视图控制器中,我创建了一个 NSMangedObjectContext,我将它传递给其他控制器,因此我始终保持在同一个上下文中。

AppDelegate *appDelegate =
[[UIApplication sharedApplication] delegate];
context =
[appDelegate managedObjectContext];

感谢您的帮助。

【问题讨论】:

【参考方案1】:

没有排序描述符,获取请求返回的对象的顺序是 不明确的。甚至不能保证两个相同的 fetch 请求返回 对象的顺序相同。

由于您的所有集合视图数据源方法都执行新的获取请求(该请求 非常无效!)关于哪个对象无话可说

Produkt* produkt = [[self refreshTableData]objectAtIndex:indexPath.row];

cellForItemAtIndexPath 中实际返回。

因此,一种可能的解决方案是将对象一次提取到 NSArray 并使用 此数组作为集合视图数据源。如果对象已被添加或修改, 执行一个新的获取请求并重新加载集合视图。

另一种可能的解决方案是使用NSFetchedResultsController (FRC)。 FRC 自动跟踪对托管对象上下文的更改并调用 如果对象被插入、删除或修改,则委托函数。如果你选择那个 路径,您应该注意,将 FRC 与集合视图一起使用有点棘手 就自动动画更新而言,与表格视图相比。但 这篇文章http://ashfurrow.com/blog/uicollectionview-example 可能会有所帮助。

【讨论】:

非常感谢,在您的建议下我解决了我的问题:)

以上是关于UICollectionview 在使用 Core Data 保存实体后重新加载数据的主要内容,如果未能解决你的问题,请参考以下文章

UICollectionView - 基于 Core Data 一对多关系的部分和行

在 Core Data 中从库中保存和获取多个图像选择

无法在UIInputViewController中使用UICollectionView进行键盘扩展

如何在 swift 中使用 @resultbuilder 使用 UICollectionView?

如何使用 UIViewControllerRepresentable 在 SwiftUI 中呈现 UICollectionView

我可以在 1 UICollectionView 中使用 collectionViewCell 2 Cell 吗?