@@ -25,29 +25,36 @@ @interface FUIArray ()
25
25
/* *
26
26
* The backing collection that holds all of the array's data.
27
27
*/
28
- @property (strong , nonatomic ) NSMutableArray <FIRDataSnapshot *> *snapshots;
28
+ @property (strong , nonatomic ) NSMutableArray <FIRDataSnapshot *> *snapshots;
29
29
30
30
/* *
31
31
* A set containing the query observer handles that should be released when
32
32
* this array is freed.
33
33
*/
34
- @property (strong , nonatomic ) NSMutableSet <NSNumber *> *handles;
34
+ @property (strong , nonatomic ) NSMutableSet <NSNumber *> *handles;
35
+
36
+ /* *
37
+ * Set to YES when any event that isn't a value event is received; set
38
+ * back to NO when receiving a value event.
39
+ * Used to keep track of whether or not the array is updating so consumers
40
+ * can more easily batch updates.
41
+ */
42
+ @property (nonatomic , assign ) BOOL isSendingUpdates;
35
43
36
44
@end
37
45
38
46
@implementation FUIArray
39
47
40
48
#pragma mark - Initializer methods
41
49
42
- - (instancetype )initWithQuery : (FIRDatabaseQuery *)query delegate : (id <FUIArrayDelegate >)delegate {
50
+ - (instancetype )initWithQuery : (FIRDatabaseQuery *)query delegate : (id <FUICollectionDelegate >)delegate {
43
51
NSParameterAssert (query != nil );
44
52
self = [super init ];
45
53
if (self) {
46
54
self.snapshots = [NSMutableArray array ];
47
55
self.query = query;
48
56
self.handles = [NSMutableSet setWithCapacity: 4 ];
49
57
self.delegate = delegate;
50
- [self initListeners ];
51
58
}
52
59
return self;
53
60
}
@@ -63,94 +70,94 @@ + (instancetype)arrayWithQuery:(id<FUIDataObservable>)query {
63
70
#pragma mark - Memory management methods
64
71
65
72
- (void )dealloc {
66
- for (NSNumber *handle in _handles) {
67
- [_query removeObserverWithHandle: handle.unsignedIntegerValue];
68
- }
73
+ [self invalidate ];
69
74
}
70
75
71
76
#pragma mark - Private API methods
72
77
73
- - (void )initListeners {
78
+ - (void )observeQuery {
79
+ if (self.handles .count == 5 ) { /* don't duplicate observers */ return ; }
74
80
FIRDatabaseHandle handle;
75
81
handle = [self .query observeEventType: FIRDataEventTypeChildAdded
76
82
andPreviousSiblingKeyWithBlock: ^(FIRDataSnapshot *snapshot, NSString *previousChildKey) {
77
- NSUInteger index = 0 ;
78
- if (previousChildKey != nil ) {
79
- index = [self indexForKey: previousChildKey] + 1 ;
80
- }
81
-
82
- [self .snapshots insertObject: snapshot atIndex: index ];
83
-
84
- if ([self .delegate respondsToSelector: @selector (array:didAddObject:atIndex: )]) {
85
- [self .delegate array: self didAddObject: snapshot atIndex: index ];
86
- }
83
+ [self didUpdate ];
84
+ [self insertSnapshot: snapshot withPreviousChildKey: previousChildKey];
87
85
}
88
86
withCancelBlock: ^(NSError *error) {
89
- if ([self .delegate respondsToSelector: @selector (array:queryCancelledWithError: )]) {
90
- [self .delegate array: self queryCancelledWithError: error];
91
- }
87
+ [self raiseError: error];
92
88
}];
93
89
[_handles addObject: @(handle)];
94
90
95
91
handle = [self .query observeEventType: FIRDataEventTypeChildChanged
96
92
andPreviousSiblingKeyWithBlock: ^(FIRDataSnapshot *snapshot, NSString *previousChildKey) {
97
- NSUInteger index = [self indexForKey: snapshot.key];
98
-
99
- [self .snapshots replaceObjectAtIndex: index withObject: snapshot];
100
-
101
- if ([self .delegate respondsToSelector: @selector (array:didChangeObject:atIndex: )]) {
102
- [self .delegate array: self didChangeObject: snapshot atIndex: index ];
103
- }
93
+ [self didUpdate ];
94
+ [self changeSnapshot: snapshot withPreviousChildKey: previousChildKey];
104
95
}
105
96
withCancelBlock: ^(NSError *error) {
106
- if ([self .delegate respondsToSelector: @selector (array:queryCancelledWithError: )]) {
107
- [self .delegate array: self queryCancelledWithError: error];
108
- }
97
+ [self raiseError: error];
109
98
}];
110
99
[_handles addObject: @(handle)];
111
100
112
101
handle = [self .query observeEventType: FIRDataEventTypeChildRemoved
113
102
andPreviousSiblingKeyWithBlock: ^(FIRDataSnapshot *snapshot, NSString *previousSiblingKey) {
114
- NSUInteger index = [self indexForKey: snapshot.key];
115
-
116
- [self .snapshots removeObjectAtIndex: index ];
117
-
118
- if ([self .delegate respondsToSelector: @selector (array:didRemoveObject:atIndex: )]) {
119
- [self .delegate array: self didRemoveObject: snapshot atIndex: index ];
120
- }
103
+ [self didUpdate ];
104
+ [self removeSnapshot: snapshot withPreviousChildKey: previousSiblingKey];
121
105
}
122
106
withCancelBlock: ^(NSError *error) {
123
- if ([self .delegate respondsToSelector: @selector (array:queryCancelledWithError: )]) {
124
- [self .delegate array: self queryCancelledWithError: error];
125
- }
107
+ [self raiseError: error];
126
108
}];
127
109
[_handles addObject: @(handle)];
128
110
129
111
handle = [self .query observeEventType: FIRDataEventTypeChildMoved
130
112
andPreviousSiblingKeyWithBlock: ^(FIRDataSnapshot *snapshot, NSString *previousChildKey) {
131
- NSUInteger fromIndex = [self indexForKey: snapshot.key];
132
- [self .snapshots removeObjectAtIndex: fromIndex];
133
-
134
- NSUInteger toIndex = 0 ;
135
- if (previousChildKey != nil ) {
136
- NSUInteger prevIndex = [self indexForKey: previousChildKey];
137
- if (prevIndex != NSNotFound ) {
138
- toIndex = prevIndex + 1 ;
139
- }
140
- }
141
-
142
- [self .snapshots insertObject: snapshot atIndex: toIndex];
143
-
144
- if ([self .delegate respondsToSelector: @selector (array:didMoveObject:fromIndex:toIndex: )]) {
145
- [self .delegate array: self didMoveObject: snapshot fromIndex: fromIndex toIndex: toIndex];
146
- }
113
+ [self didUpdate ];
114
+ [self moveSnapshot: snapshot withPreviousChildKey: previousChildKey];
147
115
}
148
116
withCancelBlock: ^(NSError *error) {
149
- if ([self .delegate respondsToSelector: @selector (array:queryCancelledWithError: )]) {
150
- [self .delegate array: self queryCancelledWithError: error];
151
- }
117
+ [self raiseError: error];
152
118
}];
153
119
[_handles addObject: @(handle)];
120
+
121
+ handle = [self .query observeEventType: FIRDataEventTypeValue
122
+ andPreviousSiblingKeyWithBlock: ^(FIRDataSnapshot *snapshot, NSString *previousChildKey) {
123
+ [self didFinishUpdates ];
124
+ }
125
+ withCancelBlock: ^(NSError *error) {
126
+ [self raiseError: error];
127
+ }];
128
+ [_handles addObject: @(handle)];
129
+ }
130
+
131
+ // Must be called from every non-value event listener in order to work correctly.
132
+ - (void )didUpdate {
133
+ if (self.isSendingUpdates ) {
134
+ return ;
135
+ }
136
+ self.isSendingUpdates = YES ;
137
+ if ([self .delegate respondsToSelector: @selector (arrayDidBeginUpdates: )]) {
138
+ [self .delegate arrayDidBeginUpdates: self ];
139
+ }
140
+ }
141
+
142
+ // Must be called from a value event listener.
143
+ - (void )didFinishUpdates {
144
+ if (!self.isSendingUpdates ) { /* This is probably an error */ return ; }
145
+ self.isSendingUpdates = NO ;
146
+ if ([self .delegate respondsToSelector: @selector (arrayDidEndUpdates: )]) {
147
+ [self .delegate arrayDidEndUpdates: self ];
148
+ }
149
+ }
150
+
151
+ - (void )raiseError : (NSError *)error {
152
+ if ([self .delegate respondsToSelector: @selector (array:queryCancelledWithError: )]) {
153
+ [self .delegate array: self queryCancelledWithError: error];
154
+ }
155
+ }
156
+
157
+ - (void )invalidate {
158
+ for (NSNumber *handle in _handles) {
159
+ [_query removeObserverWithHandle: handle.unsignedIntegerValue];
160
+ }
154
161
}
155
162
156
163
- (NSUInteger )indexForKey : (NSString *)key {
@@ -164,6 +171,69 @@ - (NSUInteger)indexForKey:(NSString *)key {
164
171
return NSNotFound ;
165
172
}
166
173
174
+ - (void )insertSnapshot : (FIRDataSnapshot *)snap withPreviousChildKey : (NSString *)previous {
175
+ NSUInteger index = 0 ;
176
+ if (previous != nil ) {
177
+ index = [self indexForKey: previous] + 1 ;
178
+ }
179
+
180
+ [self .snapshots insertObject: snap atIndex: index ];
181
+
182
+ if ([self .delegate respondsToSelector: @selector (array:didAddObject:atIndex: )]) {
183
+ [self .delegate array: self didAddObject: snap atIndex: index ];
184
+ }
185
+ }
186
+
187
+ - (void )removeSnapshot : (FIRDataSnapshot *)snap withPreviousChildKey : (NSString *)previous {
188
+ NSUInteger index = [self indexForKey: snap.key];
189
+
190
+ [self .snapshots removeObjectAtIndex: index ];
191
+
192
+ if ([self .delegate respondsToSelector: @selector (array:didRemoveObject:atIndex: )]) {
193
+ [self .delegate array: self didRemoveObject: snap atIndex: index ];
194
+ }
195
+ }
196
+
197
+ - (void )changeSnapshot : (FIRDataSnapshot *)snap withPreviousChildKey : (NSString *)previous {
198
+ NSUInteger index = [self indexForKey: snap.key];
199
+
200
+ [self .snapshots replaceObjectAtIndex: index withObject: snap];
201
+
202
+ if ([self .delegate respondsToSelector: @selector (array:didChangeObject:atIndex: )]) {
203
+ [self .delegate array: self didChangeObject: snap atIndex: index ];
204
+ }
205
+ }
206
+
207
+ - (void )moveSnapshot : (FIRDataSnapshot *)snap withPreviousChildKey : (NSString *)previous {
208
+ NSUInteger fromIndex = [self indexForKey: snap.key];
209
+ [self .snapshots removeObjectAtIndex: fromIndex];
210
+
211
+ NSUInteger toIndex = 0 ;
212
+ if (previous != nil ) {
213
+ NSUInteger prevIndex = [self indexForKey: previous];
214
+ if (prevIndex != NSNotFound ) {
215
+ toIndex = prevIndex + 1 ;
216
+ }
217
+ }
218
+ [self .snapshots insertObject: snap atIndex: toIndex];
219
+
220
+ if ([self .delegate respondsToSelector: @selector (array:didMoveObject:fromIndex:toIndex: )]) {
221
+ [self .delegate array: self didMoveObject: snap fromIndex: fromIndex toIndex: toIndex];
222
+ }
223
+ }
224
+
225
+ - (void )removeSnapshotAtIndex : (NSUInteger )index {
226
+ [self .snapshots removeObjectAtIndex: index ];
227
+ }
228
+
229
+ - (void )insertSnapshot : (FIRDataSnapshot *)snap atIndex : (NSUInteger )index {
230
+ [self .snapshots insertObject: snap atIndex: index ];
231
+ }
232
+
233
+ - (void )addSnapshot : (FIRDataSnapshot *)snap {
234
+ [self .snapshots addObject: snap];
235
+ }
236
+
167
237
#pragma mark - Public API methods
168
238
169
239
- (NSArray *)items {
@@ -174,7 +244,7 @@ - (NSUInteger)count {
174
244
return [self .snapshots count ];
175
245
}
176
246
177
- - (FIRDataSnapshot *)objectAtIndex : ( NSUInteger )index {
247
+ - (FIRDataSnapshot *)snapshotAtIndex : ( NSInteger )index {
178
248
return (FIRDataSnapshot *)[self .snapshots objectAtIndex: index ];
179
249
}
180
250
@@ -183,7 +253,7 @@ - (FIRDatabaseReference *)refForIndex:(NSUInteger)index {
183
253
}
184
254
185
255
- (id )objectAtIndexedSubscript : (NSUInteger )index {
186
- return [self objectAtIndex :index ];
256
+ return [self snapshotAtIndex :index ];
187
257
}
188
258
189
259
- (void )setObject : (id )obj atIndexedSubscript : (NSUInteger )index {
0 commit comments