Permalink
Browse files

Initial commit.

  • Loading branch information...
0 parents commit 995230c923f8f962935e2bcf087d4293927f7525 Ash Furrow committed Sep 16, 2012
Showing with 235 additions and 0 deletions.
  1. +18 −0 AFMasterViewController.h
  2. +210 −0 AFMasterViewController.m
  3. +7 −0 README.md
@@ -0,0 +1,18 @@
+//
+// AFMasterViewController.h
+// UICollectionViewExample
+//
+// Created by Ash Furrow on 2012-09-11.
+// Copyright (c) 2012 Ash Furrow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+#import <CoreData/CoreData.h>
+
+@interface AFMasterViewController : UICollectionViewController <NSFetchedResultsControllerDelegate>
+
+@property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
+@property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
+
+@end
@@ -0,0 +1,210 @@
+//
+// AFMasterViewController.m
+// UICollectionViewExample
+//
+// Created by Ash Furrow on 2012-09-11.
+// Copyright (c) 2012 Ash Furrow. All rights reserved.
+//
+
+#import "AFMasterViewController.h"
+#import "AFCollectionViewCell.h"
+
+static NSString *CellIdentifier = @"AFCollectionViewCell";
+
+@implementation AFMasterViewController
+{
+ NSMutableArray *_objectChanges;
+ NSMutableArray *_sectionChanges;
+}
+
+- (void)awakeFromNib
+{
+ [super awakeFromNib];
+}
+
+- (void)viewDidLoad
+{
+ [super viewDidLoad];
+ // Do any additional setup after loading the view, typically from a nib.
+
+ _objectChanges = [NSMutableArray array];
+ _sectionChanges = [NSMutableArray array];
+}
+
+- (void)didReceiveMemoryWarning
+{
+ [super didReceiveMemoryWarning];
+ // Dispose of any resources that can be recreated.
+}
+
+#pragma mark - UICollectionVIew
+
+- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
+{
+ return [[self.fetchedResultsController sections] count];
+}
+
+- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
+{
+
+ id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];
+ return [sectionInfo numberOfObjects];
+}
+
+// The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
+- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
+{
+ AFCollectionViewCell *cell = (AFCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
+
+ NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
+
+#warning Unimplement Cell Configuration
+
+ return cell;
+}
+
+#pragma mark - Fetched results controller
+
+- (NSFetchedResultsController *)fetchedResultsController
+{
+ if (_fetchedResultsController != nil) {
+ return _fetchedResultsController;
+ }
+
+#warning Unimplemented fetched results controller
+
+ NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
+ // Edit the entity name as appropriate.
+ NSEntityDescription *entity = [NSEntityDescription entityForName:<#entity#>inManagedObjectContext:self.managedObjectContext];
+ [fetchRequest setEntity:entity];
+
+ // Set the batch size to a suitable number.
+ [fetchRequest setFetchBatchSize:<#batch size#>];
+
+ // Edit the sort key as appropriate.
+ NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:<#descriptor#> ascending:NO];
+ NSArray *sortDescriptors = @[sortDescriptor];
+
+ [fetchRequest setSortDescriptors:sortDescriptors];
+
+ // Edit the section name key path and cache name if appropriate.
+ // nil for section name key path means "no sections".
+ 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
@@ -0,0 +1,7 @@
+# `UICollectionView+NSFetchedResultsController`
+
+This is an example of how to use the new `UICollectionView` with `NSFetchedResultsController`. The trick is to queue the updates made through the `NSFetchedResultsControllerDelegate` until the controller *finishes* its updates.
+
+# Setup
+
+Clone the repo and look in the `UICollectionViewControllre` subclass. The logic inside the `.m` file shows how to queue updates.

0 comments on commit 995230c

Please sign in to comment.