简体   繁体   English

从核心数据加载UICollectionView

[英]load UICollectionView from core data

I'm developing an iOS app and at a certain point I store images draw by the user in Core Data. 我正在开发一个iOS应用程序,并且在某个时刻我将用户绘制的图像存储在Core Data中。 Now I would like to load all the recorded images in a UICollectionView so the user could select one and share it on social networks. 现在我想在UICollectionView中加载所有录制的图像,以便用户可以选择一个并在社交网络上共享。 Everything in my app works except this last part. 我的应用程序中的所有内容都工作,除了最后一部 I followed all sorts of tutorials on the net but all examples I could find on UICollectionView were using images from Flickr or similar websites. 我在网上关注了各种各样的教程,但我在UICollectionView上找到的所有例子都使用了Flickr或类似网站的图片。

Here is my code at this point: 这是我的代码:

#import "LibraryViewController.h" (The name of the class we're in)
#import "SocialViewController.h"
#import "CollectionViewCell.h"


static NSString *cellIdentifier = @"MemeCell";

@implementation LibraryViewController {
    NSMutableArray *_objectChanges;
    NSMutableArray *_sectionChanges;
}


#pragma mark - View Controller LifeCycle

- (void)awakeFromNib
{
    [super awakeFromNib];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    _objectChanges = [NSMutableArray array];
    _sectionChanges = [NSMutableArray array];

    self.title = @"Meme collection";
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"share"]) {
        NSIndexPath *indexPath = [[self.collectionView indexPathsForSelectedItems] lastObject];
        NSManagedObject *object = [[self fetchedResultsController] objectAtIndexPath:indexPath];
        SocialViewController *destViewController = segue.destinationViewController;
        [destViewController setDetailItem:object];
    }
}

#pragma mark - UICollectionView

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{

    id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];
    return [sectionInfo numberOfObjects];
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    CollectionViewCell *cell = (CollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier
                                                                                           forIndexPath:indexPath];

    NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
    [cell setImage:[UIImage imageWithData:[object valueForKey:@"image"]]];

    return cell;
}


#pragma mark - Fetched results controller

- (NSFetchedResultsController *)fetchedResultsController
{
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // Edit the entity name as appropriate.
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Meme" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];

    [fetchRequest setFetchBatchSize:20];
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@"Master"];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;

    NSError *error = nil;
    if (![self.fetchedResultsController performFetch:&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.
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
}

    return _fetchedResultsController;
}

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
       atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
    NSMutableDictionary *change = [NSMutableDictionary new];

    switch(type) {
        case NSFetchedResultsChangeInsert:
            change[@(type)] = @(sectionIndex);
            break;
        case NSFetchedResultsChangeDelete:
            change[@(type)] = @(sectionIndex);
            break;
    }

    [_sectionChanges addObject:change];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
   atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
  newIndexPath:(NSIndexPath *)newIndexPath
{
    NSMutableDictionary *change = [NSMutableDictionary new];
    switch(type)
    {
        case NSFetchedResultsChangeInsert:
            change[@(type)] = newIndexPath;
            break;
        case NSFetchedResultsChangeDelete:
            change[@(type)] = indexPath;
            break;
        case NSFetchedResultsChangeUpdate:
            change[@(type)] = indexPath;
            break;
        case NSFetchedResultsChangeMove:
            change[@(type)] = @[indexPath, newIndexPath];
            break;
    }
    [_objectChanges addObject:change];
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
    if ([_sectionChanges count] > 0)
    {
        [self.collectionView performBatchUpdates:^{

            for (NSDictionary *change in _sectionChanges)
            {
                [change enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, id obj, BOOL *stop) {

                    NSFetchedResultsChangeType type = [key unsignedIntegerValue];
                    switch (type)
                    {
                        case NSFetchedResultsChangeInsert:
                            [self.collectionView insertSections:[NSIndexSet indexSetWithIndex:[obj unsignedIntegerValue]]];
                            break;
                        case NSFetchedResultsChangeDelete:
                            [self.collectionView deleteSections:[NSIndexSet indexSetWithIndex:[obj unsignedIntegerValue]]];
                            break;
                        case NSFetchedResultsChangeUpdate:
                            [self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:[obj unsignedIntegerValue]]];
                            break;
                    }
                }];
            }
        } completion:nil];
    }

    if ([_objectChanges count] > 0 && [_sectionChanges count] == 0)
    {
        [self.collectionView performBatchUpdates:^{

            for (NSDictionary *change in _objectChanges)
            {
                [change enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, id obj, BOOL *stop) {

                    NSFetchedResultsChangeType type = [key unsignedIntegerValue];
                    switch (type)
                    {
                        case NSFetchedResultsChangeInsert:
                            [self.collectionView insertItemsAtIndexPaths:@[obj]];
                            break;
                        case NSFetchedResultsChangeDelete:
                            [self.collectionView deleteItemsAtIndexPaths:@[obj]];
                            break;
                        case NSFetchedResultsChangeUpdate:
                            [self.collectionView reloadItemsAtIndexPaths:@[obj]];
                            break;
                        case NSFetchedResultsChangeMove:
                            [self.collectionView moveItemAtIndexPath:obj[0] toIndexPath:obj[1]];
                            break;
                    }
                }];
            }
        } completion:nil];
    }

    [_sectionChanges removeAllObjects];
    [_objectChanges removeAllObjects];
}

@end

When I run and try to access this ViewController, the app crashes with this error message: 2013-07-25 23:08:11.832 MemeGen[87259:c07] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name 'Meme'' * First throw call stack: 当我运行并尝试访问此ViewController时,应用程序崩溃并显示以下错误消息:2013-07-25 23:08:11.832 MemeGen [87259:c07] *由于未捕获的异常'NSInvalidArgumentException'而终止应用程序,原因:'+ entityForName :nil不是合法的NSManagedObjectContext参数,用于搜索实体名称'Meme''* First throw call stack:

and it points to this line of code: 它指向这行代码:

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Meme" inManagedObjectContext:self.managedObjectContext];

Obviously the self.managedObjectContext is nil. 显然self.managedObjectContext是nil。 How should I assign it? 我该如何分配? And when the user launches the application for the first time and the core data is empty, how should I manage it ? 当用户第一次启动应用程序并且核心数据为空时,我该如何管理它? Forbidding its access as long as there are no images? 只要没有图像,禁止访问?

Otherwise, I know how to store the draw images on the file system. 否则,我知道如何将绘制图像存储在文件系统上。 If someone knew a way to load it in the UICollectionView it could also be a solution I could accept. 如果有人知道在UICollectionView中加载它的方法,它也可以是我能接受的解决方案。

I would not recommend storing images in core data unless you are using the external storage functionality. 除非您使用外部存储功能,否则我不建议将图像存储在核心数据中。 Large binary objects are rarely something you want to store inside something like core data. 大型二进制对象很少是您想要存储在核心数据之类的东西。 You can, of course, store filesystem paths or URLs on core data objects that point to images on the filesystem. 当然,您可以在指向文件系统上的图像的核心数据对象上存储文件系统路径或URL。

To use Core Data with a UICollectionView, take a look at NSFetchedResultsController. 要将Core Data与UICollectionView一起使用,请查看NSFetchedResultsController。 Here's an example of using the two together to get you started. 这是一个将两者结合使用以帮助您入门的示例

You will want to get a reference to your ManagedObjectContext. 您将需要获取对ManagedObjectContext的引用。 Oftentimes this gets created in your application delegate. 通常,这会在您的应用程序委托中创建。 In which case you will want something like this - 在这种情况下你会想要这样的东西 -

NSManagedObjectContext *aManagedObjectContext = ((AppDelegate *)[UIApplication sharedApplication].delegate).managedObjectContext;

If you want you can do this in your viewDidLoad and assign it to self.managedObjectContext. 如果需要,可以在viewDidLoad中执行此操作并将其分配给self.managedObjectContext。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM