Skip to content
This repository has been archived by the owner on Jan 7, 2018. It is now read-only.

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
Ash Furrow committed Sep 16, 2012
0 parents commit 995230c
Show file tree
Hide file tree
Showing 3 changed files with 235 additions and 0 deletions.
18 changes: 18 additions & 0 deletions AFMasterViewController.h
Original file line number Diff line number Diff line change
@@ -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
210 changes: 210 additions & 0 deletions AFMasterViewController.m
Original file line number Diff line number Diff line change
@@ -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
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.