Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for batch updating with multiple transform lists #27

Merged
merged 7 commits into from Jul 31, 2013
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