From c35678e6820d59299343c72a5237484e82c0fefb Mon Sep 17 00:00:00 2001 From: Matthew Purland Date: Mon, 16 Sep 2013 10:44:00 -0700 Subject: [PATCH 1/4] Updated CueTableReloader with properties for custom animations for insert, delete, and update. Fixed issue relating to oldSection to newSection for newIndexes. --- CueTableReloader/CueTableReloader.h | 25 +++++++++++++++--- CueTableReloader/CueTableReloader.m | 40 +++++++++++++++++------------ 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/CueTableReloader/CueTableReloader.h b/CueTableReloader/CueTableReloader.h index 178b5d7..09fa2aa 100644 --- a/CueTableReloader/CueTableReloader.h +++ b/CueTableReloader/CueTableReloader.h @@ -1,3 +1,4 @@ + /* * Copyright 2013 CueTableReloader Authors. * @@ -22,7 +23,6 @@ */ @interface CueTableReloader : NSObject - /** * Preferred method of initialization. */ @@ -43,20 +43,37 @@ * Default: YES * If you know that pre-existing rows aren't subject to change, set this to NO and skip reloading them. */ -@property BOOL reloadUnchangedRows; +@property (nonatomic, assign) BOOL reloadUnchangedRows; /** * Default: NO * By default, setting an empty array will not animate. */ -@property BOOL animateClear; +@property (nonatomic, assign) BOOL animateClear; /** * Default: NO * By default, setting data for the first time will not animate. */ -@property BOOL animatePopulate; +@property (nonatomic, assign) BOOL animatePopulate; + +/** + * Default: UITableViewRowAnimationLeft + * Animation for a table row insert. + */ +@property (nonatomic, assign) UITableViewRowAnimation insertAnimation; +/** + * Default: UITableViewRowAnimationRight + * Animation for a table row delete. + */ +@property (nonatomic, assign) UITableViewRowAnimation deleteAnimation; + +/** + * Default: UITableViewRowAnimationFade + * Animation for a table row update. + */ +@property (nonatomic, assign) UITableViewRowAnimation updateAnimation; @end diff --git a/CueTableReloader/CueTableReloader.m b/CueTableReloader/CueTableReloader.m index f72a248..13c2cbe 100644 --- a/CueTableReloader/CueTableReloader.m +++ b/CueTableReloader/CueTableReloader.m @@ -16,19 +16,26 @@ #import "CueTableReloader.h" -@implementation CueTableReloader { +@interface CueTableReloader () { UITableView *_tableView; NSArray *_oldSections; } -- (id)initWithTableView:(UITableView *)tableView; -{ +@end + +@implementation CueTableReloader + +- (id)initWithTableView:(UITableView *)tableView { self = [super init]; + if (self) { _tableView = tableView; _reloadUnchangedRows = YES; _animateClear = NO; _animatePopulate = NO; + _insertAnimation = UITableViewRowAnimationLeft; + _deleteAnimation = UITableViewRowAnimationRight; + _updateAnimation = UITableViewRowAnimationFade; } return self; } @@ -53,7 +60,7 @@ - (void)reloadData:(NSArray *)sections animated:(BOOL)animated; if (!shouldAnimate) { [_tableView reloadData]; - } else { + } else { // Apply a simple algorithm to each section. // It's very good at handling new and deleted rows, not so much with reorderings. // It will not catch cross-section moves, and doesn't handle section count changes well. @@ -65,10 +72,10 @@ - (void)reloadData:(NSArray *)sections animated:(BOOL)animated; newSection = sections[i]; } else { [_tableView deleteSections:[NSIndexSet indexSetWithIndex:i] - withRowAnimation:UITableViewRowAnimationNone]; + withRowAnimation: _deleteAnimation]; if (i == 0) { [_tableView insertSections:[NSIndexSet indexSetWithIndex:0] - withRowAnimation:UITableViewRowAnimationNone]; + withRowAnimation:_insertAnimation]; } continue; } @@ -77,11 +84,11 @@ - (void)reloadData:(NSArray *)sections animated:(BOOL)animated; oldSection = _oldSections[i]; } else if (i > 0) { [_tableView insertSections:[NSIndexSet indexSetWithIndex:i] - withRowAnimation:UITableViewRowAnimationFade]; + withRowAnimation:_insertAnimation]; } NSMutableDictionary *newIndexes = [NSMutableDictionary dictionaryWithCapacity:newSection.count]; - for (int i = 0; i < oldSection.count; ++i) { + for (int i = 0; i < newSection.count; ++i) { NSObject *item = newSection[i]; newIndexes[item.tableItemKey] = @(i); } @@ -91,7 +98,7 @@ - (void)reloadData:(NSArray *)sections animated:(BOOL)animated; NSObject *item = oldSection[i]; oldIndexes[item.tableItemKey] = @(i); } - + NSMutableArray *deletions = [@[] mutableCopy]; NSMutableArray *insertions = [@[] mutableCopy]; NSMutableArray *reloads = [@[] mutableCopy]; @@ -108,7 +115,7 @@ - (void)reloadData:(NSArray *)sections animated:(BOOL)animated; NSIndexPath *insertPath = [NSIndexPath indexPathForRow:insertionIndex inSection:i]; NSIndexPath *deletePath = [NSIndexPath indexPathForRow:oldIndex inSection:i]; NSIndexPath *reloadPath = [NSIndexPath indexPathForRow:insertionIndex inSection:i]; - + NSObject *oldItem = nil; if (oldIndex < oldSection.count) { // Delete oldItem = oldSection[oldIndex]; @@ -135,8 +142,8 @@ - (void)reloadData:(NSArray *)sections animated:(BOOL)animated; continue; } else { if (oldIndexes[newItem.tableItemKey]) { // Move - int iOld = [oldIndexes[oldItem.tableItemKey] intValue]; - int iNew = [newIndexes[oldItem.tableItemKey] intValue]; + NSInteger iOld = [oldIndexes[oldItem.tableItemKey] integerValue]; + NSInteger iNew = [newIndexes[oldItem.tableItemKey] integerValue]; NSInteger diff = iNew - iOld; NSIndexPath *from = [NSIndexPath indexPathForRow:oldIndex inSection:i]; NSIndexPath *to = [NSIndexPath indexPathForRow:oldIndex+diff inSection:i]; @@ -156,18 +163,19 @@ - (void)reloadData:(NSArray *)sections animated:(BOOL)animated; "and that the ordering is constant!"]; } } + [_tableView beginUpdates]; [_tableView deleteRowsAtIndexPaths:deletions - withRowAnimation:UITableViewRowAnimationNone]; + withRowAnimation:_deleteAnimation]; [_tableView insertRowsAtIndexPaths:insertions - withRowAnimation:UITableViewRowAnimationFade]; + withRowAnimation:_insertAnimation]; for (NSArray *pair in moves) { [_tableView moveRowAtIndexPath:pair[0] toIndexPath:pair[1]]; } [_tableView endUpdates]; if (_reloadUnchangedRows) { [_tableView reloadRowsAtIndexPaths:reloads - withRowAnimation:UITableViewRowAnimationNone]; + withRowAnimation:_updateAnimation]; } } @catch (NSException *e) { [_tableView reloadData]; @@ -181,4 +189,4 @@ - (void)reloadData:(NSArray *)sections animated:(BOOL)animated; _oldSections = deepCopy; } -@end +@end \ No newline at end of file From 34630a0ec5ede7ec2bbbd8a54da6824c1831b9b8 Mon Sep 17 00:00:00 2001 From: Matthew Purland Date: Mon, 16 Sep 2013 10:59:31 -0700 Subject: [PATCH 2/4] Added CocoaPods spec --- CueTableReloader.podspec | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 CueTableReloader.podspec diff --git a/CueTableReloader.podspec b/CueTableReloader.podspec new file mode 100644 index 0000000..6141648 --- /dev/null +++ b/CueTableReloader.podspec @@ -0,0 +1,16 @@ +Pod::Spec.new do |s| + s.name = 'CueTableReloader' + s.version = '0.0.1' + s.license = { :type => 'Apache License, Version 2.0', :file => 'LICENSE' } + s.summary = 'CueTableReloader' + s.homepage = 'https://github.com/Cue/CueTableReloader' + s.author = { 'Aaron Sarazan' => 'https://github.com/Cue/CueTableReloader' } + s.source = { :git => 'https://github.com/Cue/CueTableReloader.git', :commit => 'eff314d703e9e8e57b07c5026af722bde9a3e94b' } + s.description = 'A really handy class that automatically figures out insertions, deletions, moves, and reloads in UITableView based on unique item keys.' + s.platform = :ios, '6.0' + s.ios.deployment_target = '6.0' + s.source_files = 'CueTableReloader/**/*.{h,m}' + s.public_header_files = 'CueTableReloader/**/*.h' + s.framework = 'UIKit', 'QuartzCore' + s.requires_arc = true +end From d0035fd5d1559db9143b3112c31ccf8bca0a5193 Mon Sep 17 00:00:00 2001 From: Matthew Purland Date: Mon, 16 Sep 2013 14:16:42 -0700 Subject: [PATCH 3/4] Updated default insert, delete, and update animations. Updated collections for deletions, insertions, reloads, and moves to sets. Added intersection detection for duplicates in the case of matching index paths in both deletions and insertions (also reloads) and instead simply reload based on the index path if intersection is found. --- CueTableReloader/CueTableReloader.h | 6 ++-- CueTableReloader/CueTableReloader.m | 46 ++++++++++++++++++++++------- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/CueTableReloader/CueTableReloader.h b/CueTableReloader/CueTableReloader.h index 09fa2aa..ba40d8b 100644 --- a/CueTableReloader/CueTableReloader.h +++ b/CueTableReloader/CueTableReloader.h @@ -58,19 +58,19 @@ @property (nonatomic, assign) BOOL animatePopulate; /** - * Default: UITableViewRowAnimationLeft + * Default: UITableViewRowAnimationRight * Animation for a table row insert. */ @property (nonatomic, assign) UITableViewRowAnimation insertAnimation; /** - * Default: UITableViewRowAnimationRight + * Default: UITableViewRowAnimationLeft * Animation for a table row delete. */ @property (nonatomic, assign) UITableViewRowAnimation deleteAnimation; /** - * Default: UITableViewRowAnimationFade + * Default: UITableViewRowAnimationNone * Animation for a table row update. */ @property (nonatomic, assign) UITableViewRowAnimation updateAnimation; diff --git a/CueTableReloader/CueTableReloader.m b/CueTableReloader/CueTableReloader.m index 13c2cbe..9609d08 100644 --- a/CueTableReloader/CueTableReloader.m +++ b/CueTableReloader/CueTableReloader.m @@ -33,9 +33,9 @@ - (id)initWithTableView:(UITableView *)tableView { _reloadUnchangedRows = YES; _animateClear = NO; _animatePopulate = NO; - _insertAnimation = UITableViewRowAnimationLeft; - _deleteAnimation = UITableViewRowAnimationRight; - _updateAnimation = UITableViewRowAnimationFade; + _insertAnimation = UITableViewRowAnimationRight; + _deleteAnimation = UITableViewRowAnimationLeft; + _updateAnimation = UITableViewRowAnimationNone; } return self; } @@ -99,10 +99,10 @@ - (void)reloadData:(NSArray *)sections animated:(BOOL)animated; oldIndexes[item.tableItemKey] = @(i); } - NSMutableArray *deletions = [@[] mutableCopy]; - NSMutableArray *insertions = [@[] mutableCopy]; - NSMutableArray *reloads = [@[] mutableCopy]; - NSMutableArray *moves = [@[] mutableCopy]; + NSMutableSet *deletions = [NSMutableSet set]; + NSMutableSet *insertions = [NSMutableSet set]; + NSMutableSet *reloads = [NSMutableSet set]; + NSMutableSet *moves = [NSMutableSet set]; int oldIndex = 0; int newIndex = 0; int insertionIndex = 0; @@ -164,19 +164,45 @@ - (void)reloadData:(NSArray *)sections animated:(BOOL)animated; } } + NSMutableSet *updatedReloads = [NSMutableSet set]; + + // Find intersecting index paths in deletions + for (id obj in deletions) { + if ([insertions containsObject: obj]) { + [updatedReloads addObject: obj]; + } + } + + // Find intersecting index paths in insertions + for (id obj in insertions) { + if ([deletions containsObject: obj]) { + [updatedReloads addObject: obj]; + } + } + + NSMutableSet *deletionsCopy = [deletions mutableCopy]; + NSMutableSet *insertionsCopy = [insertions mutableCopy]; + [deletions minusSet: insertionsCopy]; + [insertions minusSet: deletionsCopy]; + deletionsCopy = nil; + insertionsCopy = nil; + [_tableView beginUpdates]; - [_tableView deleteRowsAtIndexPaths:deletions + [_tableView deleteRowsAtIndexPaths:[deletions allObjects] withRowAnimation:_deleteAnimation]; - [_tableView insertRowsAtIndexPaths:insertions + [_tableView insertRowsAtIndexPaths:[insertions allObjects] withRowAnimation:_insertAnimation]; for (NSArray *pair in moves) { [_tableView moveRowAtIndexPath:pair[0] toIndexPath:pair[1]]; } [_tableView endUpdates]; if (_reloadUnchangedRows) { - [_tableView reloadRowsAtIndexPaths:reloads + [_tableView reloadRowsAtIndexPaths:[reloads allObjects] withRowAnimation:_updateAnimation]; } + + // Reload updated index paths based on intersecting index paths above (if applicable) + [_tableView reloadRowsAtIndexPaths:[updatedReloads allObjects] withRowAnimation: _updateAnimation]; } @catch (NSException *e) { [_tableView reloadData]; } From f38c8c45a13662eaf5b6bc7fddea21b7571a8d59 Mon Sep 17 00:00:00 2001 From: Matthew Purland Date: Mon, 16 Sep 2013 14:21:03 -0700 Subject: [PATCH 4/4] Updated default table insert and delete animations --- CueTableReloader/CueTableReloader.h | 4 ++-- CueTableReloader/CueTableReloader.m | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CueTableReloader/CueTableReloader.h b/CueTableReloader/CueTableReloader.h index ba40d8b..bf04a34 100644 --- a/CueTableReloader/CueTableReloader.h +++ b/CueTableReloader/CueTableReloader.h @@ -58,13 +58,13 @@ @property (nonatomic, assign) BOOL animatePopulate; /** - * Default: UITableViewRowAnimationRight + * Default: UITableViewRowAnimationLeft * Animation for a table row insert. */ @property (nonatomic, assign) UITableViewRowAnimation insertAnimation; /** - * Default: UITableViewRowAnimationLeft + * Default: UITableViewRowAnimationRight * Animation for a table row delete. */ @property (nonatomic, assign) UITableViewRowAnimation deleteAnimation; diff --git a/CueTableReloader/CueTableReloader.m b/CueTableReloader/CueTableReloader.m index 9609d08..3e40e55 100644 --- a/CueTableReloader/CueTableReloader.m +++ b/CueTableReloader/CueTableReloader.m @@ -33,8 +33,8 @@ - (id)initWithTableView:(UITableView *)tableView { _reloadUnchangedRows = YES; _animateClear = NO; _animatePopulate = NO; - _insertAnimation = UITableViewRowAnimationRight; - _deleteAnimation = UITableViewRowAnimationLeft; + _insertAnimation = UITableViewRowAnimationLeft; + _deleteAnimation = UITableViewRowAnimationRight; _updateAnimation = UITableViewRowAnimationNone; } return self;