Skip to content

Commit

Permalink
Merge pull request #27 from Raizlabs/ND-BatchCachingFix
Browse files Browse the repository at this point in the history
Fix for batch updating with multiple transform lists
  • Loading branch information
joe-goullaud committed Jul 31, 2013
2 parents db365ae + 85f9b85 commit c43d886
Show file tree
Hide file tree
Showing 9 changed files with 340 additions and 107 deletions.
2 changes: 1 addition & 1 deletion RZCollectionList/Classes/RZArrayCollectionList.h
Expand Up @@ -10,7 +10,7 @@
#import "RZCollectionListProtocol.h"
#import "RZBaseCollectionList.h"

@interface RZArrayCollectionListSectionInfo : NSObject <RZCollectionListSectionInfo, NSCopying>
@interface RZArrayCollectionListSectionInfo : NSObject <RZCollectionListSectionInfo>

@property (nonatomic, assign) NSUInteger indexOffset;

Expand Down
126 changes: 63 additions & 63 deletions RZCollectionList/Classes/RZArrayCollectionList.m
Expand Up @@ -14,10 +14,13 @@ @interface RZArrayCollectionListSectionInfo ()

@property (nonatomic, readwrite) NSString *name;
@property (nonatomic, readwrite) NSString *indexTitle;
@property (nonatomic, strong, readwrite) NSArray *objects;
@property (nonatomic, assign, readwrite) NSUInteger numberOfObjects;

@property (nonatomic, weak) RZArrayCollectionList *arrayList;

@property (nonatomic, assign) BOOL isCachedCopy;

- (NSRange)range;

@end
Expand Down Expand Up @@ -57,6 +60,10 @@ - (void)removeSectionAtIndex:(NSUInteger)index sendNotifications:(BOOL)shouldSen
// Helpers for batch update
- (NSIndexPath*)previousIndexPathForObject:(id)object;

// if not in a batch update, send necessary notifications, etc
- (void)prepareForUpdateIfNecessary;
- (void)finalizeUpdateIfNecessary;

- (void)sendDidChangeObjectNotification:(id)object atIndexPath:(NSIndexPath*)indexPath forChangeType:(RZCollectionListChangeType)type newIndexPath:(NSIndexPath*)newIndexPath;
- (void)sendDidChangeSectionNotification:(id<RZCollectionListSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(RZCollectionListChangeType)type;

Expand Down Expand Up @@ -193,17 +200,9 @@ - (void)addObject:(id)object toSection:(NSUInteger)section

- (void)insertObject:(id)object atIndexPath:(NSIndexPath*)indexPath
{
if (!self.batchUpdating)
{
[self sendWillChangeContentNotifications];
}

[self prepareForUpdateIfNecessary];
[self insertObject:object atIndexPath:indexPath sendNotifications:!self.batchUpdating];

if (!self.batchUpdating)
{
[self sendDidChangeContentNotifications];
}
[self finalizeUpdateIfNecessary];
}

- (void)removeObject:(id)object
Expand All @@ -218,47 +217,23 @@ - (void)removeObject:(id)object

- (void)removeObjectAtIndexPath:(NSIndexPath*)indexPath
{
if (!self.batchUpdating)
{
[self sendWillChangeContentNotifications];
}

[self prepareForUpdateIfNecessary];
[self removeObjectAtIndexPath:indexPath sendNotifications:!self.batchUpdating];

if (!self.batchUpdating)
{
[self sendDidChangeContentNotifications];
}
[self finalizeUpdateIfNecessary];
}

- (void)replaceObjectAtIndexPath:(NSIndexPath*)indexPath withObject:(id)object
{
if (!self.batchUpdating)
{
[self sendWillChangeContentNotifications];
}

[self prepareForUpdateIfNecessary];
[self replaceObjectAtIndexPath:indexPath withObject:object sendNotifications:!self.batchUpdating];

if (!self.batchUpdating)
{
[self sendDidChangeContentNotifications];
}
[self finalizeUpdateIfNecessary];
}

- (void)moveObjectAtIndexPath:(NSIndexPath*)sourceIndexPath toIndexPath:(NSIndexPath*)destinationIndexPath
{
if (!self.batchUpdating)
{
[self sendWillChangeContentNotifications];
}

[self prepareForUpdateIfNecessary];
[self moveObjectAtIndexPath:sourceIndexPath toIndexPath:destinationIndexPath sendNotifications:!self.batchUpdating];

if (!self.batchUpdating)
{
[self sendDidChangeContentNotifications];
}
[self finalizeUpdateIfNecessary];
}

- (void)removeAllObjects
Expand All @@ -277,17 +252,9 @@ - (void)addSection:(RZArrayCollectionListSectionInfo*)section

- (void)insertSection:(RZArrayCollectionListSectionInfo*)section atIndex:(NSUInteger)index
{
if (!self.batchUpdating)
{
[self sendWillChangeContentNotifications];
}

[self prepareForUpdateIfNecessary];
[self insertSection:section atIndex:index sendNotifications:!self.batchUpdating];

if (!self.batchUpdating)
{
[self sendDidChangeContentNotifications];
}
[self finalizeUpdateIfNecessary];
}

- (void)removeSection:(RZArrayCollectionListSectionInfo*)section
Expand All @@ -299,17 +266,9 @@ - (void)removeSection:(RZArrayCollectionListSectionInfo*)section

- (void)removeSectionAtIndex:(NSUInteger)index
{
if (!self.batchUpdating)
{
[self sendWillChangeContentNotifications];
}

[self prepareForUpdateIfNecessary];
[self removeSectionAtIndex:index sendNotifications:!self.batchUpdating];

if (!self.batchUpdating)
{
[self sendDidChangeContentNotifications];
}
[self finalizeUpdateIfNecessary];
}

- (void)beginUpdates
Expand All @@ -321,7 +280,7 @@ - (void)beginUpdates

// shallow copy sections
self.sourceSectionsInfoBeforeUpdateShallow = [self.sectionsInfo copy];
self.sourceSectionsInfoBeforeUpdateDeep = [[NSArray alloc] initWithArray:self.sectionsInfo copyItems:YES];
self.sourceSectionsInfoBeforeUpdateDeep = [self.sectionsInfo valueForKey:@"cachedCopy"];

[self sendWillChangeContentNotifications];
}
Expand All @@ -334,6 +293,11 @@ - (void)endUpdates
[self processPendingChangeNotifications];
[self sendAllPendingChangeNotifications];
[self sendDidChangeContentNotifications];

self.sourceObjectsBeforeUpdate = nil;
self.sourceSectionsInfoBeforeUpdateShallow = nil;
self.sourceSectionsInfoBeforeUpdateDeep = nil;

self.batchUpdating = NO;
}
}
Expand Down Expand Up @@ -618,6 +582,25 @@ - (NSIndexPath*)previousIndexPathForObject:(id)object

#pragma mark - Notification Helpers

- (void)prepareForUpdateIfNecessary
{
if (!self.batchUpdating)
{
// always need to have valid cached sections before sending willChange
self.sourceSectionsInfoBeforeUpdateDeep = [self.sectionsInfo valueForKey:@"cachedCopy"];
[self sendWillChangeContentNotifications];
}
}

- (void)finalizeUpdateIfNecessary
{
if (!self.batchUpdating)
{
[self sendDidChangeContentNotifications];
self.sourceSectionsInfoBeforeUpdateDeep = nil;
}
}

- (void)sendDidChangeObjectNotification:(id)object atIndexPath:(NSIndexPath*)indexPath forChangeType:(RZCollectionListChangeType)type newIndexPath:(NSIndexPath*)newIndexPath
{
#if kRZCollectionListNotificationsLogging
Expand Down Expand Up @@ -733,7 +716,7 @@ - (void)objectUpdateNotificationReceived:(NSNotification*)notification
{
[self sendWillChangeContentNotifications];

[self sendDidChangeObjectNotification:object atIndexPath:indexPath forChangeType:RZCollectionListChangeUpdate newIndexPath:nil];
[self sendDidChangeObjectNotification:object atIndexPath:indexPath forChangeType:RZCollectionListChangeUpdate newIndexPath:indexPath];

[self sendDidChangeContentNotifications];
}
Expand Down Expand Up @@ -856,6 +839,16 @@ - (NSArray*)sections
return [self.sectionsInfo copy];
}

- (NSArray*)cachedSections
{
// if we aren't updating, just return regular sections
if (nil != self.sourceSectionsInfoBeforeUpdateDeep)
{
return [self.sourceSectionsInfoBeforeUpdateDeep copy];
}
return self.sections;
}

- (NSArray*)sectionIndexTitles
{
NSMutableArray *indexTitles = [NSMutableArray arrayWithCapacity:self.sectionsInfo.count];
Expand Down Expand Up @@ -987,6 +980,10 @@ - (NSString*)indexTitle

- (NSArray*)objects
{
if (self.isCachedCopy)
{
return _objects;
}
return [self.arrayList.listObjects subarrayWithRange:NSMakeRange(self.indexOffset, self.numberOfObjects)];
}

Expand All @@ -1000,10 +997,13 @@ - (NSString*)description
return [NSString stringWithFormat:@"%@ Name:%@ IndexTitle:%@ IndexOffset:%u NumberOfObjects:%u", [super description], self.name, self.indexTitle, self.indexOffset, self.numberOfObjects];
}

- (id)copyWithZone:(NSZone *)zone
- (id<RZCollectionListSectionInfo>)cachedCopy
{
RZArrayCollectionListSectionInfo *copy = [[RZArrayCollectionListSectionInfo alloc] initWithName:self.name sectionIndexTitle:self.indexTitle numberOfObjects:self.numberOfObjects];
copy.arrayList = self.arrayList;
copy.indexOffset = self.indexOffset;
copy.objects = self.objects;
copy.isCachedCopy = YES;
return copy;
}

Expand Down
19 changes: 9 additions & 10 deletions RZCollectionList/Classes/RZBaseCollectionList.h
Expand Up @@ -11,17 +11,16 @@

/***************************************************************
*
* Base class for providing common variables and
* utils for RZCollectionList "source" lists, i.e.
* lists that maintain/represent a concrete collection
* of objects, rather than a "modified" collection.
*
* Currently used as subclass for RZFetchedCollectionList
* and RZArrayCollectionList.
* Base class for providing common variables and
* utils for classes implementing the RZCollectionList protocol.
*
* This class implements the protocol but requires subclasses
* to override the protocol methods, or an exception will be
* thrown.
* Classes implementing the protocol are not required to use this
* as a base class.
*
* This class implements the protocol itself, but requires
* subclasses to override the protocol methods, or a runtime
* exception will be thrown when an unimplemented method is
* called.
*
****************************************************************/

Expand Down
15 changes: 13 additions & 2 deletions RZCollectionList/Classes/RZBaseCollectionList.m
Expand Up @@ -178,7 +178,7 @@ - (void)cacheSectionNotificationWithSectionInfo:(id<RZCollectionListSectionInfo>
- (void)sendWillChangeContentNotifications
{
#if kRZCollectionListNotificationsLogging
NSLog(@"RZFilteredCollectionList Will Change");
NSLog(@"%@ Will Change", self);
#endif
[[self.collectionListObservers allObjects] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj conformsToProtocol:@protocol(RZCollectionListObserver)])
Expand All @@ -191,7 +191,7 @@ - (void)sendWillChangeContentNotifications
- (void)sendDidChangeContentNotifications
{
#if kRZCollectionListNotificationsLogging
NSLog(@"RZFilteredCollectionList Did Change");
NSLog(@"%@ Did Change", self);
#endif
[[self.collectionListObservers allObjects] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj conformsToProtocol:@protocol(RZCollectionListObserver)])
Expand Down Expand Up @@ -288,6 +288,9 @@ - (void)sendSectionNotifications:(NSArray *)sectionNotifications
[[self.collectionListObservers allObjects] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj conformsToProtocol:@protocol(RZCollectionListObserver)])
{
#if kRZCollectionListNotificationsLogging
NSLog(@"%@ Changed Section %@", self, notification);
#endif
[obj collectionList:self didChangeSection:(id<RZCollectionListSectionInfo>)notification.sectionInfo atIndex:notification.sectionIndex forChangeType:notification.type];
}
}];
Expand All @@ -300,6 +303,9 @@ - (void)sendObjectNotifications:(NSArray *)objectNotifications
[[self.collectionListObservers allObjects] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj conformsToProtocol:@protocol(RZCollectionListObserver)])
{
#if kRZCollectionListNotificationsLogging
NSLog(@"%@ Changed Object %@", self, notification);
#endif
[obj collectionList:self didChangeObject:notification.object atIndexPath:notification.indexPath forChangeType:notification.type newIndexPath:notification.nuIndexPath];
}
}];
Expand Down Expand Up @@ -353,6 +359,11 @@ - (NSArray*)sections
@throw [self missingProtocolMethodExceptionWithSelector:_cmd];
}

- (NSArray*)cachedSections
{
@throw [self missingProtocolMethodExceptionWithSelector:_cmd];
}

- (NSArray*)sectionIndexTitles
{
@throw [self missingProtocolMethodExceptionWithSelector:_cmd];
Expand Down
11 changes: 11 additions & 0 deletions RZCollectionList/Classes/RZCollectionListProtocol.h
Expand Up @@ -17,15 +17,26 @@
@property (nonatomic, assign, readonly) NSUInteger numberOfObjects;
@property (nonatomic, readonly) NSArray *objects;

//! Return a copy of this object which returns STATIC values for all properties above
/*!
This is different from NSCopying in the sense that a cachedCopy of section info
should not derive its property values from a dynamic source (source list, etc)
but rather should return a static value for each property.
*/
- (id<RZCollectionListSectionInfo>)cachedCopy;

@end

@protocol RZCollectionListDelegate;
@protocol RZCollectionListObserver;

@protocol RZCollectionList <NSObject>

@required

@property (nonatomic, readonly) NSArray *listObjects;
@property (nonatomic, readonly) NSArray *sections;
@property (nonatomic, readonly) NSArray *cachedSections; // sections cached prior to update, cleared when update is finished
@property (nonatomic, readonly) NSArray *listObservers;
@property (nonatomic, weak) id<RZCollectionListDelegate> delegate;

Expand Down

0 comments on commit c43d886

Please sign in to comment.