1 Star 0 Fork 0

iOSDevLog/FirebaseUI-iOS

加入 Gitee
与超过 1400万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
FUIArray.m 10.74 KB
一键复制 编辑 原始数据 按行查看 历史
Morgan Chen 提交于 2019-05-30 04:20 +08:00 . Fix tests and disable UI tests
// clang-format off
//
// Copyright (c) 2016 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// clang-format on
#import "FUIArray.h"
@interface FUIArray ()
/**
* The backing collection that holds all of the array's data.
*/
@property (strong, nonatomic) NSMutableArray<FIRDataSnapshot *> *snapshots;
/**
* The backing collection that holds all of the array's keys.
*/
@property (strong, nonatomic) NSMutableArray<NSString *> *keys;
/**
* A set containing the query observer handles that should be released when
* this array is freed.
*/
@property (strong, nonatomic) NSMutableSet<NSNumber *> *handles;
/**
* Set to YES when any event that isn't a value event is received; set
* back to NO when receiving a value event.
* Used to keep track of whether or not the array is updating so consumers
* can more easily batch updates.
*/
@property (nonatomic, assign) BOOL isSendingUpdates;
@end
@implementation FUIArray
#pragma mark - Initializer methods
- (instancetype)initWithQuery:(FIRDatabaseQuery *)query delegate:(id<FUICollectionDelegate>)delegate {
NSParameterAssert(query != nil);
self = [super init];
if (self) {
self.snapshots = [NSMutableArray array];
self.keys = [NSMutableArray array];
self.query = query;
self.handles = [NSMutableSet setWithCapacity:4];
self.delegate = delegate;
}
return self;
}
- (instancetype)initWithQuery:(id<FUIDataObservable>)query {
return [self initWithQuery:query delegate:nil];
}
+ (instancetype)arrayWithQuery:(id<FUIDataObservable>)query {
return [[self alloc] initWithQuery:query];
}
#pragma mark - Memory management methods
- (void)dealloc {
[self invalidate];
}
#pragma mark - Private API methods
- (void)observeQuery {
if (self.handles.count == 5) { /* don't duplicate observers */ return; }
FIRDatabaseHandle handle;
handle = [self.query observeEventType:FIRDataEventTypeChildAdded
andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *previousChildKey) {
[self didUpdate];
[self insertSnapshot:snapshot withPreviousChildKey:previousChildKey];
}
withCancelBlock:^(NSError *error) {
[self raiseError:error];
}];
[_handles addObject:@(handle)];
handle = [self.query observeEventType:FIRDataEventTypeChildChanged
andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *previousChildKey) {
[self didUpdate];
[self changeSnapshot:snapshot withPreviousChildKey:previousChildKey];
}
withCancelBlock:^(NSError *error) {
[self raiseError:error];
}];
[_handles addObject:@(handle)];
handle = [self.query observeEventType:FIRDataEventTypeChildRemoved
andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *previousSiblingKey) {
[self didUpdate];
[self removeSnapshot:snapshot withPreviousChildKey:previousSiblingKey];
}
withCancelBlock:^(NSError *error) {
[self raiseError:error];
}];
[_handles addObject:@(handle)];
handle = [self.query observeEventType:FIRDataEventTypeChildMoved
andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *previousChildKey) {
[self didUpdate];
[self moveSnapshot:snapshot withPreviousChildKey:previousChildKey];
}
withCancelBlock:^(NSError *error) {
[self raiseError:error];
}];
[_handles addObject:@(handle)];
handle = [self.query observeEventType:FIRDataEventTypeValue
andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *previousChildKey) {
[self didFinishUpdates];
}
withCancelBlock:^(NSError *error) {
[self raiseError:error];
}];
[_handles addObject:@(handle)];
}
// Must be called from every non-value event listener in order to work correctly.
- (void)didUpdate {
if (self.isSendingUpdates) {
return;
}
self.isSendingUpdates = YES;
if ([self.delegate respondsToSelector:@selector(arrayDidBeginUpdates:)]) {
[self.delegate arrayDidBeginUpdates:self];
}
}
// Must be called from a value event listener.
- (void)didFinishUpdates {
if (!self.isSendingUpdates) { /* This is probably an error */ return; }
self.isSendingUpdates = NO;
if ([self.delegate respondsToSelector:@selector(arrayDidEndUpdates:)]) {
[self.delegate arrayDidEndUpdates:self];
}
}
- (void)raiseError:(NSError *)error {
if ([self.delegate respondsToSelector:@selector(array:queryCancelledWithError:)]) {
[self.delegate array:self queryCancelledWithError:error];
}
}
- (void)invalidate {
for (NSNumber *handle in _handles) {
[_query removeObserverWithHandle:handle.unsignedIntegerValue];
}
[self.handles removeAllObjects];
// Remove all values on invalidation.
[self didUpdate];
for (NSInteger i = 0; i < self.snapshots.count; /* no i++ since we modify the array instead */ ) {
FIRDataSnapshot *current = self.snapshots[i];
[self.snapshots removeObjectAtIndex:i];
[self.keys removeObjectAtIndex:i];
if ([self.delegate respondsToSelector:@selector(array:didRemoveObject:atIndex:)]) {
[self.delegate array:self didRemoveObject:current atIndex:i];
}
}
[self didFinishUpdates];
}
- (NSUInteger)indexForKey:(NSString *)key {
NSParameterAssert(key != nil);
return [self.keys indexOfObject:key];
}
- (void)insertSnapshot:(FIRDataSnapshot *)snap withPreviousChildKey:(NSString *)previous {
NSUInteger index = 0;
if (previous != nil) {
NSInteger previousChildIndex = (NSInteger)[self indexForKey:previous];
if (previousChildIndex == NSNotFound) {
NSString *reason = [NSString stringWithFormat:@"Attempted to insert snapshot with unknown"
@" previousChildKey %@ into array: %@", previous, self.snapshots];
NSException *exception = [NSException exceptionWithName:NSInternalInconsistencyException
reason:reason
userInfo:nil];
@throw exception;
}
index = previousChildIndex + 1;
}
[self.snapshots insertObject:snap atIndex:index];
[self.keys insertObject:snap.key atIndex:index];
if ([self.delegate respondsToSelector:@selector(array:didAddObject:atIndex:)]) {
[self.delegate array:self didAddObject:snap atIndex:index];
}
}
- (void)removeSnapshot:(FIRDataSnapshot *)snap withPreviousChildKey:(NSString *)previous {
NSUInteger index = [self indexForKey:snap.key];
if (index == NSNotFound) {
NSString *reason = [NSString stringWithFormat:@"Attempted to remove snapshot with unknown"
@" key %@ from array: %@", snap.key, self.snapshots];
NSException *exception = [NSException exceptionWithName:NSInternalInconsistencyException
reason:reason
userInfo:nil];
@throw exception;
}
[self.snapshots removeObjectAtIndex:index];
[self.keys removeObjectAtIndex:index];
if ([self.delegate respondsToSelector:@selector(array:didRemoveObject:atIndex:)]) {
[self.delegate array:self didRemoveObject:snap atIndex:index];
}
}
- (void)changeSnapshot:(FIRDataSnapshot *)snap withPreviousChildKey:(NSString *)previous {
NSUInteger index = [self indexForKey:snap.key];
if (index == NSNotFound) {
NSString *reason = [NSString stringWithFormat:@"Attempted to replace snapshot with unknown"
@" key %@ in array: %@", snap.key, self.snapshots];
NSException *exception = [NSException exceptionWithName:NSInternalInconsistencyException
reason:reason
userInfo:nil];
@throw exception;
}
[self.snapshots replaceObjectAtIndex:index withObject:snap];
[self.keys replaceObjectAtIndex:index withObject:snap.key];
if ([self.delegate respondsToSelector:@selector(array:didChangeObject:atIndex:)]) {
[self.delegate array:self didChangeObject:snap atIndex:index];
}
}
- (void)moveSnapshot:(FIRDataSnapshot *)snap withPreviousChildKey:(NSString *)previous {
NSUInteger fromIndex = [self indexForKey:snap.key];
if (fromIndex == NSNotFound) {
NSString *reason = [NSString stringWithFormat:@"Attempted to remove snapshot with unknown"
@" key %@ from array: %@", snap.key, self.snapshots];
NSException *exception = [NSException exceptionWithName:NSInternalInconsistencyException
reason:reason
userInfo:nil];
@throw exception;
}
[self.snapshots removeObjectAtIndex:fromIndex];
[self.keys removeObjectAtIndex:fromIndex];
NSUInteger toIndex = 0;
if (previous != nil) {
NSUInteger prevIndex = [self indexForKey:previous];
if (prevIndex != NSNotFound) {
toIndex = prevIndex + 1;
}
}
[self.snapshots insertObject:snap atIndex:toIndex];
[self.keys insertObject:snap.key atIndex:toIndex];
if ([self.delegate respondsToSelector:@selector(array:didMoveObject:fromIndex:toIndex:)]) {
[self.delegate array:self didMoveObject:snap fromIndex:fromIndex toIndex:toIndex];
}
}
- (void)removeSnapshotAtIndex:(NSUInteger)index {
[self.snapshots removeObjectAtIndex:index];
[self.keys removeObjectAtIndex:index];
}
- (void)insertSnapshot:(FIRDataSnapshot *)snap atIndex:(NSUInteger)index {
[self.snapshots insertObject:snap atIndex:index];
[self.keys insertObject:snap.key atIndex:index];
}
- (void)addSnapshot:(FIRDataSnapshot *)snap {
[self.snapshots addObject:snap];
[self.keys addObject:snap.key];
}
#pragma mark - Public API methods
- (NSArray *)items {
return [self.snapshots copy];
}
- (NSUInteger)count {
return [self.snapshots count];
}
- (FIRDataSnapshot *)snapshotAtIndex:(NSInteger)index {
return (FIRDataSnapshot *)[self.snapshots objectAtIndex:index];
}
- (FIRDatabaseReference *)refForIndex:(NSUInteger)index {
return [(FIRDataSnapshot *)[self.snapshots objectAtIndex:index] ref];
}
- (id)objectAtIndexedSubscript:(NSUInteger)index {
return [self snapshotAtIndex:index];
}
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)index {
@throw [NSException exceptionWithName:@"FUIArraySetIndexWithSubscript"
reason:@"Setting an object as FUIArray[i] is not supported."
userInfo:nil];
}
@end
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/iOSDevLog/FirebaseUI-iOS.git
git@gitee.com:iOSDevLog/FirebaseUI-iOS.git
iOSDevLog
FirebaseUI-iOS
FirebaseUI-iOS
master

搜索帮助