Skip to content

Commit 18f2af3

Browse files
committed
Lots of refactoring to get section deletion to work. InitialOpenSections and SectionsAlwaysOpen should now properly work with section deletion.
1 parent 6c08795 commit 18f2af3

File tree

2 files changed

+79
-76
lines changed

2 files changed

+79
-76
lines changed

Example/Testing_Example/FZAccordionTableViewExample/FirstViewController.m

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,26 @@ - (void)setupData {
4040
- (void)setupTableView {
4141
self.tableView.allowsMultipleSelectionDuringEditing = NO;
4242
self.tableView.allowMultipleSectionsOpen = NO;
43+
self.tableView.keepOneSectionOpen = YES;
44+
// self.tableView.initialOpenSections = [NSSet setWithObjects:@(1), nil];
45+
4346
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:kTableViewCellReuseIdentifier];
4447
// [self.tableView registerClass:[FZAccordionTableViewHeaderView class] forHeaderFooterViewReuseIdentifier:kAccordionHeaderViewReuseIdentifier];
4548
[self.tableView registerNib:[UINib nibWithNibName:@"AccordionHeaderView" bundle:nil] forHeaderFooterViewReuseIdentifier:kAccordionHeaderViewReuseIdentifier];
49+
// [self testDeletingMultipleSectionsAtTheSameTime];
50+
}
51+
52+
- (void)testDeletingMultipleSectionsAtTheSameTime {
53+
self.tableView.sectionsAlwaysOpen =[NSSet setWithObjects:@(0), @(2), nil];
54+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
55+
NSMutableIndexSet *indexSet = [NSMutableIndexSet new];
56+
[indexSet addIndex:0];
57+
[indexSet addIndex:2];
58+
59+
[self.sections removeObjectAtIndex:2];
60+
[self.sections removeObjectAtIndex:0];
61+
[self.tableView deleteSections:indexSet withRowAnimation:UITableViewRowAnimationFade];
62+
});
4663
}
4764

4865
#pragma mark - Class Overrides -

FZAccordionTableView/FZAccordionTableView.m

Lines changed: 62 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,15 @@
3030
#import <objc/runtime.h>
3131

3232
#pragma mark -
33-
#pragma mark - FZAccordionTableViewSection
33+
#pragma mark - FZAccordionTableViewSectionInfo
3434
#pragma mark -
3535

36-
@interface FZAccordionTableViewSection : NSObject
36+
@interface FZAccordionTableViewSectionInfo : NSObject
3737
@property (nonatomic, getter=isOpen) BOOL open;
3838
@property (nonatomic) NSInteger numberOfRows;
3939
@end
4040

41-
@implementation FZAccordionTableViewSection
41+
@implementation FZAccordionTableViewSectionInfo
4242
- (instancetype)initWithNumberOfRows:(NSInteger)numberOfRows {
4343
if (self = [super init]) {
4444
_numberOfRows = numberOfRows;
@@ -55,7 +55,6 @@ @protocol FZAccordionTableViewHeaderViewDelegate;
5555

5656
@interface FZAccordionTableViewHeaderView()
5757

58-
//@property (nonatomic) NSInteger section;
5958
@property (nonatomic, weak) id <FZAccordionTableViewHeaderViewDelegate> delegate;
6059

6160
@end
@@ -99,9 +98,8 @@ @interface FZAccordionTableView() <UITableViewDataSource, UITableViewDelegate, F
9998
@property id<UITableViewDelegate, FZAccordionTableViewDelegate> subclassDelegate;
10099
@property id<UITableViewDataSource> subclassDataSource;
101100

102-
//@property (strong, nonatomic) NSMutableSet *openedSections;
103-
//@property (strong, nonatomic) NSMutableDictionary *numOfRowsForSection;
104-
@property (strong, nonatomic) NSMutableArray <FZAccordionTableViewSection *> *sections; // <FZAccordionTableViewSection *>
101+
@property (strong, nonatomic) NSMutableSet *mutableInitialOpenSections;
102+
@property (strong, nonatomic) NSMutableArray <FZAccordionTableViewSectionInfo *> *sectionInfos;
105103

106104
@end
107105

@@ -138,9 +136,7 @@ - (id)init {
138136
}
139137

140138
- (void)initializeVars {
141-
// _openedSections = [[NSMutableSet alloc] init];
142-
// _numOfRowsForSection = [NSMutab
143-
_sections = [NSMutableArray new];
139+
_sectionInfos = [NSMutableArray new];
144140
_allowMultipleSectionsOpen = NO;
145141
_enableAnimationFix = NO;
146142
_keepOneSectionOpen = NO;
@@ -149,24 +145,24 @@ - (void)initializeVars {
149145
#pragma mark - Helper methods -
150146

151147
- (BOOL)isSectionOpen:(NSInteger)section {
152-
return [self.sections[section] isOpen];
148+
return [self.sectionInfos[section] isOpen];
153149
}
154150

155151
- (BOOL)isAlwaysOpenedSection:(NSInteger)section {
156152
return [self.sectionsAlwaysOpen containsObject:@(section)];
157153
}
158154

159155
- (void)addOpenedSection:(NSInteger)section { // KRIS TODO: Rename this to markSectionOpen
160-
[self.sections[section] setOpen:YES];
156+
[self.sectionInfos[section] setOpen:YES];
161157
}
162158

163159
- (void)removeOpenedSection:(NSInteger)section {
164-
[self.sections[section] setOpen:NO];
160+
[self.sectionInfos[section] setOpen:NO];
165161
}
166162

167163
- (NSArray *)getIndexPathsForSection:(NSInteger)section {
168164

169-
NSInteger numOfRows = [self.sections[section] numberOfRows];
165+
NSInteger numOfRows = [self.sectionInfos[section] numberOfRows];
170166
NSMutableArray *indexPaths = [NSMutableArray array];
171167
for (int row = 0; row < numOfRows; row++) {
172168
[indexPaths addObject:[NSIndexPath indexPathForRow:row inSection:section]];
@@ -202,6 +198,7 @@ - (NSInteger)sectionForHeaderView:(UITableViewHeaderFooterView *)headerView {
202198
}
203199
else {
204200
maxSection = middleSection-1;
201+
section = maxSection; // Occurs when headerView sticks to the top
205202
}
206203
}
207204

@@ -222,13 +219,25 @@ - (void)setDataSource:(id<UITableViewDataSource>)dataSource {
222219

223220
- (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation {
224221

225-
[sections enumerateIndexesUsingBlock:^(NSUInteger section, BOOL * _Nonnull stop) {
226-
[self.sections removeObjectAtIndex:section];
227-
// KRIS TODO: If the removed section is one that needs ot be oepned, we need to open the next section.
228-
// OR Refactor sections open to just be a delegate call "canOpen Section
229-
// [self.openedSections removeObject:@(section)];
222+
// Remove section info in reverse order to prevent array from
223+
// removing the wrong section due to the stacking effect of arrays
224+
[sections enumerateIndexesWithOptions:NSEnumerationReverse usingBlock:^(NSUInteger section, BOOL * _Nonnull stop) {
225+
[self.sectionInfos removeObjectAtIndex:section];
230226
}];
227+
231228
[super deleteSections:sections withRowAnimation:animation];
229+
230+
// Re-open any sections that were closed by deletion, but
231+
// must be always open.
232+
if (self.sectionsAlwaysOpen.count > 0) {
233+
[sections enumerateIndexesWithOptions:NSEnumerationReverse usingBlock:^(NSUInteger section, BOOL * _Nonnull stop) {
234+
if ([self.sectionsAlwaysOpen containsObject:@(section)] && ![self isSectionOpen:section]) {
235+
FZAccordionTableViewHeaderView *sectionHeaderView = (FZAccordionTableViewHeaderView *)[self headerViewForSection:section];
236+
NSArray *indexPathsToModify = [self getIndexPathsForSection:section];
237+
[self openSection:section withHeaderView:sectionHeaderView andIndexPaths:indexPathsToModify];
238+
}
239+
}];
240+
}
232241
}
233242

234243
#pragma mark - Forwarding handling -
@@ -250,24 +259,9 @@ - (BOOL)respondsToSelector:(SEL)aSelector {
250259

251260
#pragma mark - Override Setters -
252261

253-
- (void)setSectionsAlwaysOpen:(NSSet *)alwaysOpenedSections {
254-
_sectionsAlwaysOpen = alwaysOpenedSections;
255-
256-
// if (_sectionsAlwaysOpen != nil) {
257-
// for (NSNumber *alwaysOpenedSection in _sectionsAlwaysOpen) {
258-
// [self addOpenedSection:alwaysOpenedSection.integerValue];
259-
// }
260-
// }
261-
}
262-
263262
- (void)setInitialOpenSections:(NSSet *)initialOpenedSections {
264263
_initialOpenSections = initialOpenedSections;
265-
266-
// if (_initialOpenSections != nil) {
267-
// for (NSNumber *section in _initialOpenSections) {
268-
// [self addOpenedSection:section.integerValue];
269-
// }
270-
// }
264+
_mutableInitialOpenSections = [initialOpenedSections mutableCopy];
271265
}
272266

273267
#pragma mark - FZAccordionTableViewHeaderViewDelegate -
@@ -287,16 +281,16 @@ - (void)tappedHeaderView:(FZAccordionTableViewHeaderView *)sectionHeaderView {
287281
NSInteger countOfOpenSections = 0;
288282

289283
for (NSInteger i = 0; i < self.numberOfSections; i++) {
290-
if ([self.sections[i] isOpen]) {
284+
if ([self.sectionInfos[i] isOpen]) {
291285
countOfOpenSections++;
292286
}
293287
}
294288

295-
// if (self.sectionsAlwaysOpen.count > 0) { // Subtract 'sectionsAlwaysOpen' from 'openedSections'
296-
// NSMutableSet *openedSectionsCopy = [self.openedSections mutableCopy];
297-
// [openedSectionsCopy minusSet:self.sectionsAlwaysOpen];
298-
// countOfOpenSections = openedSectionsCopy.count;
299-
// }
289+
if (self.sectionsAlwaysOpen.count > 0) {
290+
// 'sectionsAlwaysOpen' does not have an influence
291+
// on 'keepOneSectionOpen'
292+
countOfOpenSections -= self.sectionsAlwaysOpen.count;
293+
}
300294

301295
if (countOfOpenSections == 1 && [self isSectionOpen:section]) {
302296
return;
@@ -336,20 +330,18 @@ - (void)openSection:(NSInteger)section withHeaderView:(FZAccordionTableViewHeade
336330
// If any section is open beneath the one we are trying to open,
337331
// animate from the bottom
338332
for (NSInteger i = section-1; i >= 0; i--) {
339-
if ([self.sections[i] isOpen]) {
333+
if ([self.sectionInfos[i] isOpen]) {
340334
insertAnimation = UITableViewRowAnimationBottom;
341335
}
342336
}
343337
}
344338

345-
// KRIS TODO: Fix
346-
// if (self.enableAnimationFix) {
347-
// if (self.openedSections.count > 0 &&
348-
// (section == self.sections.count-1 || section == self.sections.count-2) &&
349-
// !self.allowsMultipleSelection) {
350-
// insertAnimation = UITableViewRowAnimationFade;
351-
// }
352-
// }
339+
if (self.enableAnimationFix) {
340+
if (!self.allowsMultipleSelection &&
341+
(section == self.numberOfSections-1 || section == self.numberOfSections-2)) {
342+
insertAnimation = UITableViewRowAnimationFade;
343+
}
344+
}
353345

354346
[self addOpenedSection:section];
355347
[self beginUpdates];
@@ -382,7 +374,7 @@ - (void)autoCollapseAllSectionsExceptSection:(NSInteger)section {
382374
// Get all of the sections that we need to close
383375
NSMutableSet *sectionsToClose = [[NSMutableSet alloc] init];
384376
for (NSInteger i = 0; i < self.numberOfSections; i++) {
385-
FZAccordionTableViewSection *sectionInfo = self.sections[i];
377+
FZAccordionTableViewSectionInfo *sectionInfo = self.sectionInfos[i];
386378
if (section != i && sectionInfo.isOpen && ![self isAlwaysOpenedSection:i]) {
387379
[sectionsToClose addObject:@(i)];
388380
}
@@ -401,9 +393,9 @@ - (void)autoCollapseAllSectionsExceptSection:(NSInteger)section {
401393
closeAnimation = UITableViewRowAnimationBottom;
402394
}
403395
if (self.enableAnimationFix) {
404-
if ((sectionToClose.integerValue == self.sections.count - 1 ||
405-
sectionToClose.integerValue == self.sections.count - 2) &&
406-
!self.allowsMultipleSelection) {
396+
if (!self.allowsMultipleSelection &&
397+
(sectionToClose.integerValue == self.sectionInfos.count - 1 ||
398+
sectionToClose.integerValue == self.sectionInfos.count - 2)) {
407399
closeAnimation = UITableViewRowAnimationFade;
408400
}
409401
}
@@ -434,29 +426,23 @@ - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
434426
numOfSections = [self.subclassDataSource numberOfSectionsInTableView:tableView];
435427
}
436428

437-
// Initialize an empty array filled with @(0)
438-
// id sections[numOfSections];
439-
// memset(sections, (int)[NSNumber numberWithInt:0], numOfSections);
440-
// self.numberOfRowsInSection = [NSMutableArray arrayWithObjects:sections count:numOfSections];
441-
// self.numberOfRowsInSection = [NSMutableArray arrayWithCapacity:numOfSections];
442-
// NSMutableArray *newNumberOfRowsInSection = [NSMutableArray arrayWithCapacity:numOfSections];
443-
444-
for (NSInteger i = self.sections.count; i < numOfSections; i++) {
445-
FZAccordionTableViewSection *section = [[FZAccordionTableViewSection alloc] initWithNumberOfRows:0];
446-
section.open = NO;
447-
[self.sections addObject:section];
448-
// KRIS TO DO: Handle sections always open and initial open sections.
429+
// Create 'FZAccordionTableViewSectionInfo' objects to represent each section
430+
for (NSInteger i = self.sectionInfos.count; i < numOfSections; i++) {
431+
FZAccordionTableViewSectionInfo *section = [[FZAccordionTableViewSectionInfo alloc] initWithNumberOfRows:0];
432+
433+
// Account for any initial open sections
434+
if (self.mutableInitialOpenSections.count > 0 && [self.mutableInitialOpenSections containsObject:@(i)]) {
435+
section.open = YES;
436+
[self.mutableInitialOpenSections removeObject:@(i)];
437+
}
438+
// Account for sections that are always open
439+
else {
440+
section.open = [self.sectionsAlwaysOpen containsObject:@(i)];
441+
}
442+
443+
[self.sectionInfos addObject:section];
449444
}
450445

451-
452-
// First time
453-
// it's less
454-
// it's more
455-
456-
457-
// we must maintain the correct size, yet also copy in the left-over elements.
458-
459-
460446
return numOfSections;
461447
}
462448

@@ -467,7 +453,7 @@ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger
467453
if ([self.subclassDataSource respondsToSelector:@selector(tableView:numberOfRowsInSection:)]) {
468454
numOfRows = [self.subclassDataSource tableView:tableView numberOfRowsInSection:section];;
469455
}
470-
[self.sections[section] setNumberOfRows:numOfRows];
456+
[self.sectionInfos[section] setNumberOfRows:numOfRows];
471457

472458
return ([self isSectionOpen:section]) ? numOfRows : 0;
473459
}

0 commit comments

Comments
 (0)