From 46d4ff4432357718ce6d3cf18b7e22f50467de43 Mon Sep 17 00:00:00 2001 From: Phillip Calvin Date: Thu, 19 May 2016 10:19:35 -0400 Subject: [PATCH 1/5] Deferred (coalesced) updates support --- ATV/ATVTableSection.h | 3 +++ ATV/ATVTableSection.m | 12 ++++++++++++ ATV/ATVTableSection_Private.h | 1 + ATV/ATVTableView.h | 4 ++++ ATV/ATVTableView.m | 37 +++++++++++++++++++++++++++++++++++ ATV/ATVTableView_Private.h | 3 +++ 6 files changed, 60 insertions(+) diff --git a/ATV/ATVTableSection.h b/ATV/ATVTableSection.h index 29722a6..174a27f 100644 --- a/ATV/ATVTableSection.h +++ b/ATV/ATVTableSection.h @@ -80,4 +80,7 @@ toIndex:(NSUInteger)newIndex; - (void) reloadSectionWithRowAnimation:(UITableViewRowAnimation)animation; +- (void)setNeedsToPerformUpdates; +- (void)performUpdatesAnimated:(BOOL)animated; + @end diff --git a/ATV/ATVTableSection.m b/ATV/ATVTableSection.m index ef5c861..0a78957 100644 --- a/ATV/ATVTableSection.m +++ b/ATV/ATVTableSection.m @@ -1,6 +1,7 @@ #import "ATVTableSection.h" #import "ATVTableSection_Private.h" #import "ATVTableView.h" +#import "ATVTableView_Private.h" @implementation ATVTableSection @@ -202,4 +203,15 @@ - (void) deselectRowAtIndex:(NSUInteger)index animated:(BOOL)animated { [self._tableView deselectRowAtIndex:index inSection:self animated:animated]; } +#pragma mark - Deferred updates + +- (void)setNeedsToPerformUpdates { + self.needsToPerformUpdates = YES; + [self._tableView setWillPerformUpdates]; +} + +- (void)performUpdatesAnimated:(BOOL)animated { + self.needsToPerformUpdates = NO; +} + @end diff --git a/ATV/ATVTableSection_Private.h b/ATV/ATVTableSection_Private.h index 7e21290..ada7b8c 100644 --- a/ATV/ATVTableSection_Private.h +++ b/ATV/ATVTableSection_Private.h @@ -15,4 +15,5 @@ @interface ATVTableSection () @property (ATV_WEAK) ATVTableView* _tableView; @property (strong) NSMutableDictionary* registeredNibs; +@property BOOL needsToPerformUpdates; @end diff --git a/ATV/ATVTableView.h b/ATV/ATVTableView.h index c03f779..497a2fd 100644 --- a/ATV/ATVTableView.h +++ b/ATV/ATVTableView.h @@ -25,6 +25,10 @@ @property (nonatomic, strong) UIView* emptyView; @property (nonatomic) BOOL emptyViewHonorsContentInset; +#pragma mark - Deferred updates + +- (void)performUpdatesAnimated:(BOOL)animated; + #pragma mark - Private - (UITableViewCell*) cellForRowAtIndex:(NSUInteger)index inSection:(ATVTableSection*)section; diff --git a/ATV/ATVTableView.m b/ATV/ATVTableView.m index 96e69ee..08fa83e 100644 --- a/ATV/ATVTableView.m +++ b/ATV/ATVTableView.m @@ -124,6 +124,43 @@ - (void) removeAllSectionsWithRowAnimation:(UITableViewRowAnimation)animation { [self updateEmptyView]; } +#pragma mark - Deferred updates + +- (void)setWillPerformUpdates { + if (self.window) { + if (!self.willPerformUpdates) { + self.willPerformUpdates = YES; + [self performSelector:@selector(performUpdates) withObject:nil afterDelay:0.0]; + } + } +} + +- (void)didMoveToWindow { + [super didMoveToWindow]; + [self performUpdatesAnimated:NO]; +} + +- (void)performUpdates { + [self performUpdatesAnimated:YES]; +} + +- (void)performUpdatesAnimated:(BOOL)animated { + NSMutableArray *toUpdate = [NSMutableArray array]; + for (ATVTableSection *section in self.sections) { + if ([section needsToPerformUpdates]) { + [toUpdate addObject:section]; + } + } + if (toUpdate.count > 0) { + [self beginUpdates]; + for (ATVTableSection *section in toUpdate) { + [section performUpdatesAnimated:animated]; + NSAssert(![section needsToPerformUpdates], @"Section %@ still needs to perform updates after updating, did you forget to call [super performUpdates]?", self); + } + [self endUpdates]; + } + self.willPerformUpdates = NO; +} #pragma mark - Table view data source diff --git a/ATV/ATVTableView_Private.h b/ATV/ATVTableView_Private.h index f1d3d7f..eb6bebf 100644 --- a/ATV/ATVTableView_Private.h +++ b/ATV/ATVTableView_Private.h @@ -5,4 +5,7 @@ @property (strong) NSMutableArray* sections; @property UITableViewCellSeparatorStyle desiredSeparatorStyle; +@property BOOL willPerformUpdates; +- (void)setWillPerformUpdates; + @end From 6d2bdc262897869431f28ecb90aeae796ceb852e Mon Sep 17 00:00:00 2001 From: Phillip Calvin Date: Fri, 3 Jun 2016 11:51:04 -0400 Subject: [PATCH 2/5] Allow customizing animations in array section --- ATV/ATVArrayTableSection.h | 5 +++++ ATV/ATVArrayTableSection.m | 20 +++++++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/ATV/ATVArrayTableSection.h b/ATV/ATVArrayTableSection.h index 17055ab..c384a87 100644 --- a/ATV/ATVArrayTableSection.h +++ b/ATV/ATVArrayTableSection.h @@ -13,4 +13,9 @@ - (void)setObjects:(NSArray*)objects; - (void)setObjects:(NSArray*)objects animated:(BOOL)animated; +#pragma mark - Overrides + +- (UITableViewRowAnimation)animationForInsertingObject:(id)object atIndex:(NSUInteger)index; +- (UITableViewRowAnimation)animationForDeletingObject:(id)object atIndex:(NSUInteger)index; + @end diff --git a/ATV/ATVArrayTableSection.m b/ATV/ATVArrayTableSection.m index 278cd4f..4b6b72e 100644 --- a/ATV/ATVArrayTableSection.m +++ b/ATV/ATVArrayTableSection.m @@ -44,9 +44,6 @@ - (void) setObjects:(NSArray*)objects { } - (void) setObjects:(NSArray*)objects animated:(BOOL)animated { - UITableViewRowAnimation insertAnimation = animated ? UITableViewRowAnimationTop : UITableViewRowAnimationNone; - UITableViewRowAnimation deleteAnimation = animated ? UITableViewRowAnimationBottom : UITableViewRowAnimationNone; - if (!_objects) { _objects = objects; [self reloadSectionWithRowAnimation:UITableViewRowAnimationNone]; @@ -130,6 +127,8 @@ - (void) setObjects:(NSArray*)objects animated:(BOOL)animated { [self moveRowAtIndex:[oldIndex unsignedIntegerValue] toIndex:[newIndex unsignedIntegerValue]]; } } else { + UITableViewRowAnimation insertAnimation = animated ? + [self animationForInsertingObject:item atIndex:[newIndex unsignedIntegerValue]] : UITableViewRowAnimationNone; [self insertRowsAtIndices:[NSIndexSet indexSetWithIndex:[newIndex unsignedIntegerValue]] withRowAnimation:insertAnimation]; } } @@ -137,13 +136,24 @@ - (void) setObjects:(NSArray*)objects animated:(BOOL)animated { for (id item in oldIndexes) { NSArray *indexes = [oldIndexes objectForKey:item]; for (NSNumber *index in indexes) { - [deleted addIndex:[index unsignedIntegerValue]]; + id item = [oldObjects objectAtIndex:[index unsignedIntegerValue]]; + UITableViewRowAnimation deleteAnimation = animated ? + [self animationForDeletingObject:item atIndex:[index unsignedIntegerValue]] : UITableViewRowAnimationNone; + [self deleteRowsAtIndices:[NSIndexSet indexSetWithIndex:[index unsignedIntegerValue]] + withRowAnimation:deleteAnimation]; } } - [self deleteRowsAtIndices:deleted withRowAnimation:deleteAnimation]; [self endUpdates]; } +- (UITableViewRowAnimation)animationForInsertingObject:(id)object atIndex:(NSUInteger)index { + return UITableViewRowAnimationTop; +} + +- (UITableViewRowAnimation)animationForDeletingObject:(id)object atIndex:(NSUInteger)index { + return UITableViewRowAnimationBottom; +} + #pragma mark - Cell source - (UITableViewCell*) cellForRowAtIndex:(NSUInteger)index { From 3c8061cfcc93e5cfae4b703e0684d02ec11075fd Mon Sep 17 00:00:00 2001 From: Phillip Calvin Date: Fri, 3 Jun 2016 11:51:19 -0400 Subject: [PATCH 3/5] Add React-style IDs to array table section --- ATV/ATVArrayTableSection.h | 1 + ATV/ATVArrayTableSection.m | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/ATV/ATVArrayTableSection.h b/ATV/ATVArrayTableSection.h index c384a87..2597988 100644 --- a/ATV/ATVArrayTableSection.h +++ b/ATV/ATVArrayTableSection.h @@ -17,5 +17,6 @@ - (UITableViewRowAnimation)animationForInsertingObject:(id)object atIndex:(NSUInteger)index; - (UITableViewRowAnimation)animationForDeletingObject:(id)object atIndex:(NSUInteger)index; +- (id)uniqueIdentifierForObject:(id)object; @end diff --git a/ATV/ATVArrayTableSection.m b/ATV/ATVArrayTableSection.m index 4b6b72e..9d9503c 100644 --- a/ATV/ATVArrayTableSection.m +++ b/ATV/ATVArrayTableSection.m @@ -76,17 +76,19 @@ - (void) setObjects:(NSArray*)objects animated:(BOOL)animated { // if it's not a new entry. for (int i = 0; i < oldObjects.count; i++) { id item = [oldObjects objectAtIndex:i]; - NSMutableArray *positions = [oldIndexes objectForKey:item]; + id identifier = [self uniqueIdentifierForObject:item]; + NSMutableArray *positions = [oldIndexes objectForKey:identifier]; if (!positions) { positions = [NSMutableArray array]; } [positions addObject:@(i)]; - [oldIndexes setObject:positions forKey:item]; + [oldIndexes setObject:positions forKey:identifier]; } for (int i = 0; i < objects.count; i++) { id item = [objects objectAtIndex:i]; - NSMutableArray *positions = [oldIndexes objectForKey:item]; + id identifier = [self uniqueIdentifierForObject:item]; + NSMutableArray *positions = [oldIndexes objectForKey:identifier]; NSNumber *oldIndex = nil; if (positions.count > 0) { // Without loss of generality, assume this duplicate was the first. This @@ -94,7 +96,7 @@ - (void) setObjects:(NSArray*)objects animated:(BOOL)animated { oldIndex = [positions objectAtIndex:0]; [positions removeObjectAtIndex:0]; } else { - [oldIndexes removeObjectForKey:item]; + [oldIndexes removeObjectForKey:identifier]; } NSNumber *newIndex = @(i); @@ -132,9 +134,8 @@ - (void) setObjects:(NSArray*)objects animated:(BOOL)animated { [self insertRowsAtIndices:[NSIndexSet indexSetWithIndex:[newIndex unsignedIntegerValue]] withRowAnimation:insertAnimation]; } } - NSMutableIndexSet *deleted = [NSMutableIndexSet new]; - for (id item in oldIndexes) { - NSArray *indexes = [oldIndexes objectForKey:item]; + for (id identifier in oldIndexes) { + NSArray *indexes = [oldIndexes objectForKey:identifier]; for (NSNumber *index in indexes) { id item = [oldObjects objectAtIndex:[index unsignedIntegerValue]]; UITableViewRowAnimation deleteAnimation = animated ? @@ -154,6 +155,10 @@ - (UITableViewRowAnimation)animationForDeletingObject:(id)object atIndex:(NSUInt return UITableViewRowAnimationBottom; } +- (id)uniqueIdentifierForObject:(id)object { + return object; +} + #pragma mark - Cell source - (UITableViewCell*) cellForRowAtIndex:(NSUInteger)index { From 1f28bf0fe794e838532fcb21ae42da11f5335ee3 Mon Sep 17 00:00:00 2001 From: Phillip Calvin Date: Mon, 13 Jun 2016 15:01:12 -0400 Subject: [PATCH 4/5] Update visible cells when moving them UITableView doesn't seem to do this for us? --- ATV/ATVArrayTableSection.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ATV/ATVArrayTableSection.m b/ATV/ATVArrayTableSection.m index 9d9503c..6b30879 100644 --- a/ATV/ATVArrayTableSection.m +++ b/ATV/ATVArrayTableSection.m @@ -126,6 +126,11 @@ - (void) setObjects:(NSArray*)objects animated:(BOOL)animated { } } } else { + UITableViewCell *cell = [self cellAtIndex:[oldIndex unsignedIntegerValue]]; + if (cell) { + // Cell is visible, repaint it + [self configureCell:cell atIndex:[newIndex unsignedIntegerValue]]; + } [self moveRowAtIndex:[oldIndex unsignedIntegerValue] toIndex:[newIndex unsignedIntegerValue]]; } } else { From 010753d6f61edff19595b161484656e5ca24d90f Mon Sep 17 00:00:00 2001 From: Jason Sypher Date: Thu, 18 May 2017 10:27:55 -0600 Subject: [PATCH 5/5] Update for cocoapods --- ATV.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ATV.podspec b/ATV.podspec index a6220c3..ab62850 100644 --- a/ATV.podspec +++ b/ATV.podspec @@ -4,7 +4,7 @@ Pod::Spec.new do |s| s.summary = "A pluggable table view with a different data source for each section." s.homepage = "https://github.com/pnc/ATV" - s.license = 'MIT (example)' + s.license = 'MIT' s.author = { "Phil Calvin" => "pnc1138@gmail.com" } s.source = { :git => "https://github.com/pnc/ATV.git", :branch => "master" }