This repository has been archived by the owner on Jan 7, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Ash Furrow
committed
Sep 16, 2012
0 parents
commit 995230c
Showing
3 changed files
with
235 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |