@@ -25,29 +25,36 @@ @interface FUIArray ()
2525/* *
2626 * The backing collection that holds all of the array's data.
2727 */
28- @property (strong , nonatomic ) NSMutableArray <FIRDataSnapshot *> *snapshots;
28+ @property (strong , nonatomic ) NSMutableArray <FIRDataSnapshot *> *snapshots;
2929
3030/* *
3131 * A set containing the query observer handles that should be released when
3232 * this array is freed.
3333 */
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;
3543
3644@end
3745
3846@implementation FUIArray
3947
4048#pragma mark - Initializer methods
4149
42- - (instancetype )initWithQuery : (FIRDatabaseQuery *)query delegate : (id <FUIArrayDelegate >)delegate {
50+ - (instancetype )initWithQuery : (FIRDatabaseQuery *)query delegate : (id <FUICollectionDelegate >)delegate {
4351 NSParameterAssert (query != nil );
4452 self = [super init ];
4553 if (self) {
4654 self.snapshots = [NSMutableArray array ];
4755 self.query = query;
4856 self.handles = [NSMutableSet setWithCapacity: 4 ];
4957 self.delegate = delegate;
50- [self initListeners ];
5158 }
5259 return self;
5360}
@@ -63,94 +70,94 @@ + (instancetype)arrayWithQuery:(id<FUIDataObservable>)query {
6370#pragma mark - Memory management methods
6471
6572- (void )dealloc {
66- for (NSNumber *handle in _handles) {
67- [_query removeObserverWithHandle: handle.unsignedIntegerValue];
68- }
73+ [self invalidate ];
6974}
7075
7176#pragma mark - Private API methods
7277
73- - (void )initListeners {
78+ - (void )observeQuery {
79+ if (self.handles .count == 5 ) { /* don't duplicate observers */ return ; }
7480 FIRDatabaseHandle handle;
7581 handle = [self .query observeEventType: FIRDataEventTypeChildAdded
7682 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];
8785 }
8886 withCancelBlock: ^(NSError *error) {
89- if ([self .delegate respondsToSelector: @selector (array:queryCancelledWithError: )]) {
90- [self .delegate array: self queryCancelledWithError: error];
91- }
87+ [self raiseError: error];
9288 }];
9389 [_handles addObject: @(handle)];
9490
9591 handle = [self .query observeEventType: FIRDataEventTypeChildChanged
9692 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];
10495 }
10596 withCancelBlock: ^(NSError *error) {
106- if ([self .delegate respondsToSelector: @selector (array:queryCancelledWithError: )]) {
107- [self .delegate array: self queryCancelledWithError: error];
108- }
97+ [self raiseError: error];
10998 }];
11099 [_handles addObject: @(handle)];
111100
112101 handle = [self .query observeEventType: FIRDataEventTypeChildRemoved
113102 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];
121105 }
122106 withCancelBlock: ^(NSError *error) {
123- if ([self .delegate respondsToSelector: @selector (array:queryCancelledWithError: )]) {
124- [self .delegate array: self queryCancelledWithError: error];
125- }
107+ [self raiseError: error];
126108 }];
127109 [_handles addObject: @(handle)];
128110
129111 handle = [self .query observeEventType: FIRDataEventTypeChildMoved
130112 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];
147115 }
148116 withCancelBlock: ^(NSError *error) {
149- if ([self .delegate respondsToSelector: @selector (array:queryCancelledWithError: )]) {
150- [self .delegate array: self queryCancelledWithError: error];
151- }
117+ [self raiseError: error];
152118 }];
153119 [_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+ }
154161}
155162
156163- (NSUInteger )indexForKey : (NSString *)key {
@@ -164,6 +171,69 @@ - (NSUInteger)indexForKey:(NSString *)key {
164171 return NSNotFound ;
165172}
166173
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+
167237#pragma mark - Public API methods
168238
169239- (NSArray *)items {
@@ -174,7 +244,7 @@ - (NSUInteger)count {
174244 return [self .snapshots count ];
175245}
176246
177- - (FIRDataSnapshot *)objectAtIndex : ( NSUInteger )index {
247+ - (FIRDataSnapshot *)snapshotAtIndex : ( NSInteger )index {
178248 return (FIRDataSnapshot *)[self .snapshots objectAtIndex: index];
179249}
180250
@@ -183,7 +253,7 @@ - (FIRDatabaseReference *)refForIndex:(NSUInteger)index {
183253}
184254
185255- (id )objectAtIndexedSubscript : (NSUInteger )index {
186- return [self objectAtIndex : index];
256+ return [self snapshotAtIndex : index];
187257}
188258
189259- (void )setObject : (id )obj atIndexedSubscript : (NSUInteger )index {
0 commit comments