-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathNNSectionsDiff.m
More file actions
243 lines (194 loc) · 8.85 KB
/
Copy pathNNSectionsDiff.m
File metadata and controls
243 lines (194 loc) · 8.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
//
// NNSectionsDiff.m
// ArrayDiff
//
// Created by Nick Tymchenko on 03/04/14.
// Copyright (c) 2014 Nick Tymchenko. All rights reserved.
//
#import "NNSectionsDiff.h"
#import "NNSectionsDiffChange.h"
@implementation NNSectionsDiff {
@protected
NSIndexSet *_deletedSections;
NSIndexSet *_insertedSections;
NSSet *_deleted;
NSSet *_inserted;
NSSet *_changed;
}
#pragma mark - Init
- (instancetype)init {
return [self initWithDeletedSections:nil insertedSections:nil deleted:nil inserted:nil changed:nil];
}
- (instancetype)initWithDeletedSections:(NSIndexSet *)deletedSections
insertedSections:(NSIndexSet *)insertedSections
deleted:(NSSet *)deleted
inserted:(NSSet *)inserted
changed:(NSSet *)changed
{
self = [super init];
if (!self) return nil;
_deletedSections = [deletedSections copy] ?: [NSIndexSet indexSet];
_insertedSections = [insertedSections copy] ?: [NSIndexSet indexSet];
_deleted = [deleted copy] ?: [NSSet set];
_inserted = [inserted copy] ?: [NSSet set];
_changed = [changed copy] ?: [NSSet set];
[self sanitizeDeletedAndInsertedSections];
return self;
}
- (void)sanitizeDeletedAndInsertedSections {
// If a section has been deleted, it makes no sense to have separate deletions for its rows.
// The same thing about inserts.
_deleted = [_deleted objectsPassingTest:^BOOL(NSIndexPath *obj, BOOL *stop) {
return ![_deletedSections containsIndex:[obj indexAtPosition:0]];
}];
_inserted = [_inserted objectsPassingTest:^BOOL(NSIndexPath *obj, BOOL *stop) {
return ![_insertedSections containsIndex:[obj indexAtPosition:0]];
}];
}
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone {
return [[NNSectionsDiff allocWithZone:zone] initWithDeletedSections:self.deletedSections
insertedSections:self.insertedSections
deleted:self.deleted
inserted:self.inserted
changed:self.changed];
}
#pragma mark - NSMutableCopying
- (id)mutableCopyWithZone:(NSZone *)zone {
return [[NNMutableSectionsDiff allocWithZone:zone] initWithDeletedSections:self.deletedSections
insertedSections:self.insertedSections
deleted:self.deleted
inserted:self.inserted
changed:self.changed];
}
#pragma mark - NSObject
- (BOOL)isEqual:(id)other {
if (other == self) return YES;
if (!other || ![other isKindOfClass:[NNSectionsDiff class]]) return NO;
return [self isEqualToSectionsDiff:other];
}
- (BOOL)isEqualToSectionsDiff:(NNSectionsDiff *)other {
if (![self.deletedSections isEqualToIndexSet:other.deletedSections]) return NO;
if (![self.insertedSections isEqualToIndexSet:other.insertedSections]) return NO;
if (![self.deleted isEqualToSet:other.deleted]) return NO;
if (![self.inserted isEqualToSet:other.inserted]) return NO;
if (![self.changed isEqualToSet:other.changed]) return NO;
return YES;
}
- (NSUInteger)hash {
NSUInteger prime = 31;
NSUInteger result = 1;
result = prime * result + [self.deletedSections hash];
result = prime * result + [self.insertedSections hash];
result = prime * result + [self.deleted hash];
result = prime * result + [self.inserted hash];
result = prime * result + [self.changed hash];
return result;
}
- (NSString *)description {
NSMutableString *description = [NSMutableString stringWithString:[super description]];
[description appendString:@" {\n"];
if ([self.deleted count] > 0) {
[description appendFormat:@" Deleted: %@\n", [self descriptionForIndexPaths:self.deleted]];
}
if ([self.deletedSections count] > 0) {
[description appendFormat:@" Deleted sections: %@\n", [self descriptionForSections:self.deletedSections]];
}
if ([self.insertedSections count] > 0) {
[description appendFormat:@" Inserted sections: %@\n", [self descriptionForSections:self.insertedSections]];
}
if ([self.inserted count] > 0) {
[description appendFormat:@" Inserted: %@\n", [self descriptionForIndexPaths:self.inserted]];
}
if ([self.changed count] > 0) {
[description appendFormat:@" Changed: %@\n", [self descriptionForChanged:self.changed]];
}
[description appendString:@"}"];
return description;
}
- (NSString *)descriptionForSections:(NSIndexSet *)indexSet {
NSMutableArray *strings = [NSMutableArray array];
[indexSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
[strings addObject:[NSString stringWithFormat:@"%@", @(idx)]];
}];
return [strings componentsJoinedByString:@", "];
}
- (NSString *)descriptionForIndexPaths:(NSSet *)set {
NSArray *sortedIndexPaths = [set sortedArrayUsingDescriptors:@[ [NSSortDescriptor sortDescriptorWithKey:@"self" ascending:YES selector:@selector(compare:)] ]];
NSMutableArray *strings = [NSMutableArray array];
for (NSIndexPath *indexPath in sortedIndexPaths) {
[strings addObject:[NSString stringWithFormat:@"%@.%@",
@([indexPath indexAtPosition:0]),
@([indexPath indexAtPosition:1])]];
};
return [strings componentsJoinedByString:@", "];
}
- (NSString *)descriptionForChanged:(NSSet *)set {
NSArray *sortedChanges = [[set allObjects] sortedArrayUsingComparator:^NSComparisonResult(NNSectionsDiffChange *obj1, NNSectionsDiffChange *obj2) {
if ([obj1.before compare:obj2.before] != NSOrderedSame) {
return [obj1.before compare:obj2.before];
} else {
return [obj1.after compare:obj2.after];
}
}];
NSMutableArray *strings = [NSMutableArray array];
for (NNSectionsDiffChange *change in sortedChanges) {
[strings addObject:[change description]];
};
return [strings componentsJoinedByString:@", "];
}
@end
@implementation NNMutableSectionsDiff
- (instancetype)initWithDeletedSections:(NSIndexSet *)deletedSections
insertedSections:(NSIndexSet *)insertedSections
deleted:(NSSet *)deleted
inserted:(NSSet *)inserted
changed:(NSSet *)changed
{
self = [super initWithDeletedSections:deletedSections insertedSections:insertedSections deleted:deleted inserted:inserted changed:changed];
if (!self) return nil;
_deletedSections = [_deletedSections mutableCopy];
_insertedSections = [_insertedSections mutableCopy];
_deleted = [_deleted mutableCopy];
_inserted = [_inserted mutableCopy];
_changed = [_changed mutableCopy];
return self;
}
@dynamic deletedSections;
@dynamic insertedSections;
@dynamic deleted;
@dynamic inserted;
@dynamic changed;
@end
@implementation NNMutableSectionsDiff (Manipulation)
- (void)shiftBySectionDelta:(NSInteger)sectionDelta rowDelta:(NSInteger)rowDelta;
{
[self.deletedSections shiftIndexesStartingAtIndex:0 by:sectionDelta];
[self.insertedSections shiftIndexesStartingAtIndex:0 by:sectionDelta];
NSMutableSet *deleted = [NSMutableSet setWithCapacity:[self.deleted count]];
for (NSIndexPath *indexPath in self.deleted) {
[deleted addObject:[self shiftIndexPath:indexPath bySectionDelta:sectionDelta rowDelta:rowDelta]];
}
_deleted = deleted;
NSMutableSet *inserted = [NSMutableSet setWithCapacity:[self.inserted count]];
for (NSIndexPath *indexPath in self.inserted) {
[inserted addObject:[self shiftIndexPath:indexPath bySectionDelta:sectionDelta rowDelta:rowDelta]];
}
_inserted = inserted;
NSMutableSet *changed = [NSMutableSet setWithCapacity:[self.changed count]];
for (NNSectionsDiffChange *change in self.changed) {
NSIndexPath *before = [self shiftIndexPath:change.before bySectionDelta:sectionDelta rowDelta:rowDelta];
NSIndexPath *after = [self shiftIndexPath:change.after bySectionDelta:sectionDelta rowDelta:rowDelta];
[changed addObject:[[NNSectionsDiffChange alloc] initWithBefore:before after:after type:change.type]];
}
_changed = changed;
}
- (NSIndexPath *)shiftIndexPath:(NSIndexPath *)indexPath bySectionDelta:(NSInteger)sectionDelta rowDelta:(NSInteger)rowDelta
{
NSUInteger indexes[] = {
[indexPath indexAtPosition:0] + sectionDelta,
[indexPath indexAtPosition:1] + rowDelta
};
return [NSIndexPath indexPathWithIndexes:indexes length:2];
}
@end