adding pods method of package managing
This commit is contained in:
+329
@@ -0,0 +1,329 @@
|
||||
// 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 "FirebaseDatabaseUI/Sources/Public/FirebaseDatabaseUI/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
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
// 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 "FirebaseDatabaseUI/Sources/Public/FirebaseDatabaseUI/FUICollectionViewDataSource.h"
|
||||
#import "FirebaseDatabaseUI/Sources/Public/FirebaseDatabaseUI/FUIArray.h"
|
||||
|
||||
@interface FUICollectionViewDataSource () <FUICollectionDelegate>
|
||||
|
||||
@property (nonatomic, readonly, nonnull) id<FUICollection> collection;
|
||||
|
||||
/**
|
||||
* Count is tracked separately from the FUIArray to make sure
|
||||
* count isn't invalid during an animated update.
|
||||
*/
|
||||
@property (nonatomic, readwrite, assign) NSUInteger count;
|
||||
|
||||
/**
|
||||
* The callback to populate a subclass of UICollectionViewCell with an object
|
||||
* provided by the datasource.
|
||||
*/
|
||||
@property (strong, nonatomic, readonly) UICollectionViewCell *(^populateCellAtIndexPath)
|
||||
(UICollectionView *collectionView, NSIndexPath *indexPath, FIRDataSnapshot *object);
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUICollectionViewDataSource
|
||||
|
||||
#pragma mark - FUIDataSource initializer methods
|
||||
|
||||
- (instancetype)initWithCollection:(id<FUICollection>)collection
|
||||
populateCell:(UICollectionViewCell * (^)(UICollectionView *,
|
||||
NSIndexPath *,
|
||||
FIRDataSnapshot *))populateCell {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_collection = collection;
|
||||
_collection.delegate = self;
|
||||
_populateCellAtIndexPath = populateCell;
|
||||
_count = 0; // This is zero because RTDB arrays start out at zero
|
||||
// and send initial items as a series of adds.
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithQuery:(FIRDatabaseQuery *)query
|
||||
populateCell:(UICollectionViewCell *(^)(UICollectionView *,
|
||||
NSIndexPath *,
|
||||
FIRDataSnapshot *))populateCell {
|
||||
FUIArray *array = [[FUIArray alloc] initWithQuery:query];
|
||||
return [self initWithCollection:array populateCell:populateCell];
|
||||
}
|
||||
|
||||
- (NSUInteger)count {
|
||||
return _count;
|
||||
}
|
||||
|
||||
- (NSArray<FIRDataSnapshot *> *)items {
|
||||
return self.collection.items;
|
||||
}
|
||||
|
||||
- (FIRDataSnapshot *)snapshotAtIndex:(NSInteger)index {
|
||||
return [self.collection snapshotAtIndex:index];
|
||||
}
|
||||
|
||||
- (void)bindToView:(UICollectionView *)view {
|
||||
self.collectionView = view;
|
||||
view.dataSource = self;
|
||||
[self.collection observeQuery];
|
||||
}
|
||||
|
||||
- (void)unbind {
|
||||
self.collectionView.dataSource = nil;
|
||||
self.collectionView = nil;
|
||||
[self.collection invalidate];
|
||||
}
|
||||
|
||||
#pragma mark - FUICollectionDelegate methods
|
||||
|
||||
// performBatchUpdates: is used for single updates because of this radar:
|
||||
// https://openradar.appspot.com/26484150
|
||||
- (void)array:(FUIArray *)array didAddObject:(id)object atIndex:(NSUInteger)index {
|
||||
[self.collectionView performBatchUpdates:^{
|
||||
self.count = array.count;
|
||||
[self.collectionView
|
||||
insertItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:index inSection:0] ]];
|
||||
} completion:^(BOOL finished) {}];
|
||||
}
|
||||
|
||||
- (void)array:(FUIArray *)array didChangeObject:(id)object atIndex:(NSUInteger)index {
|
||||
[self.collectionView
|
||||
reloadItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:index inSection:0] ]];
|
||||
}
|
||||
|
||||
- (void)array:(FUIArray *)array didRemoveObject:(id)object atIndex:(NSUInteger)index {
|
||||
[self.collectionView performBatchUpdates:^{
|
||||
self.count = array.count;
|
||||
[self.collectionView
|
||||
deleteItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:index inSection:0] ]];
|
||||
} completion:^(BOOL finished) {}];
|
||||
}
|
||||
|
||||
- (void)array:(FUIArray *)array didMoveObject:(id)object
|
||||
fromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex {
|
||||
[self.collectionView moveItemAtIndexPath:[NSIndexPath indexPathForItem:fromIndex inSection:0]
|
||||
toIndexPath:[NSIndexPath indexPathForItem:toIndex inSection:0]];
|
||||
}
|
||||
|
||||
- (void)array:(id<FUICollection>)array queryCancelledWithError:(NSError *)error {
|
||||
if (self.queryErrorHandler != NULL) {
|
||||
self.queryErrorHandler(error);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDataSource methods
|
||||
|
||||
- (nonnull UICollectionViewCell *)collectionView:(nonnull UICollectionView *)collectionView
|
||||
cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath {
|
||||
FIRDataSnapshot *snap = [self.collection.items objectAtIndex:indexPath.item];
|
||||
|
||||
UICollectionViewCell *cell = self.populateCellAtIndexPath(collectionView, indexPath, snap);
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfSectionsInCollectionView:(nonnull UICollectionView *)collectionView {
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView
|
||||
numberOfItemsInSection:(NSInteger)section {
|
||||
return self.count;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation UICollectionView (FUICollectionViewDataSource)
|
||||
|
||||
- (FUICollectionViewDataSource *)bindToQuery:(FIRDatabaseQuery *)query
|
||||
populateCell:(UICollectionViewCell *(^)(UICollectionView *,
|
||||
NSIndexPath *,
|
||||
FIRDataSnapshot *))populateCell {
|
||||
FUICollectionViewDataSource *dataSource =
|
||||
[[FUICollectionViewDataSource alloc] initWithQuery:query populateCell:populateCell];
|
||||
[dataSource bindToView:self];
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,215 @@
|
||||
// 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 "FirebaseDatabaseUI/Sources/Public/FirebaseDatabaseUI/FUIIndexArray.h"
|
||||
#import "FirebaseDatabaseUI/Sources/Public/FirebaseDatabaseUI/FUIQueryObserver.h"
|
||||
|
||||
@interface FUIIndexArray () <FUICollectionDelegate>
|
||||
|
||||
@property (nonatomic, readonly) id<FUIDataObservable> index;
|
||||
@property (nonatomic, readonly) id<FUIDataObservable> data;
|
||||
|
||||
@property (nonatomic, readonly) FUIArray *indexArray;
|
||||
|
||||
@property (nonatomic, readonly) NSMutableArray<FUIQueryObserver *> *observers;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* FUIIndexArray manages an instance of FirebaseArray internally to
|
||||
* keep track of which queries it should be updating. The FirebaseArrayDelegate
|
||||
* methods are responsible for keeping observers up-to-date as the contents of
|
||||
* the FirebaseArray change.
|
||||
*/
|
||||
@implementation FUIIndexArray
|
||||
|
||||
- (instancetype)init {
|
||||
NSException *e =
|
||||
[NSException exceptionWithName:@"FIRUnavailableMethodException"
|
||||
reason:@"-init is unavailable. Please use the designated initializer instead."
|
||||
userInfo:nil];
|
||||
@throw e;
|
||||
}
|
||||
|
||||
- (instancetype)initWithIndex:(id<FUIDataObservable>)index
|
||||
data:(id<FUIDataObservable>)data
|
||||
delegate:(nullable id<FUIIndexArrayDelegate>)delegate; {
|
||||
NSParameterAssert(index != nil);
|
||||
NSParameterAssert(data != nil);
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_index = index;
|
||||
_data = data;
|
||||
_observers = [NSMutableArray array];
|
||||
_delegate = delegate;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithIndex:(id<FUIDataObservable>)index
|
||||
data:(id<FUIDataObservable>)data {
|
||||
return [self initWithIndex:index data:data delegate:nil];
|
||||
}
|
||||
|
||||
- (void)observeQueries {
|
||||
_indexArray = [[FUIArray alloc] initWithQuery:self.index delegate:self];
|
||||
[_indexArray observeQuery];
|
||||
}
|
||||
|
||||
- (NSArray<FIRDataSnapshot *> *)items {
|
||||
NSArray *observers = [self.observers copy];
|
||||
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:observers.count];
|
||||
for (FUIQueryObserver *observer in observers) {
|
||||
if (observer.contents != nil) {
|
||||
[array addObject:observer.contents];
|
||||
}
|
||||
}
|
||||
return [array copy];
|
||||
}
|
||||
|
||||
- (NSArray<FIRDataSnapshot *> *) indexes {
|
||||
return self.indexArray.items;
|
||||
}
|
||||
|
||||
- (NSUInteger)count {
|
||||
return self.observers.count;
|
||||
}
|
||||
|
||||
- (void)observeQuery {
|
||||
[self observeQueries];
|
||||
}
|
||||
|
||||
// FUIIndexArray instance becomes unusable after invalidation.
|
||||
- (void)invalidate {
|
||||
for (NSInteger i = 0; i < self.observers.count; i++) {
|
||||
FUIQueryObserver *observer = self.observers[i];
|
||||
[observer removeAllObservers];
|
||||
}
|
||||
_observers = nil;
|
||||
}
|
||||
|
||||
- (FIRDataSnapshot *)objectAtIndex:(NSUInteger)index {
|
||||
return self.observers[index].contents;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
#pragma mark - FirebaseArrayDelegate
|
||||
|
||||
- (void)observer:(FUIQueryObserver *)obs
|
||||
didFinishLoadWithSnap:(FIRDataSnapshot *)snap
|
||||
error:(NSError *)error {
|
||||
// Need to look up location in array to account for possible moves
|
||||
NSUInteger index = [self.observers indexOfObject:obs];
|
||||
|
||||
if (error != nil) {
|
||||
if ([self.delegate respondsToSelector:@selector(array:reference:atIndex:didFailLoadWithError:)]) {
|
||||
[self.delegate array:self reference:obs.query atIndex:index didFailLoadWithError:error];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ([self.delegate respondsToSelector:@selector(array:reference:didLoadObject:atIndex:)]) {
|
||||
[self.delegate array:self reference:obs.query didLoadObject:snap atIndex:index];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)array:(FUIArray *)array
|
||||
didAddObject:(FIRDataSnapshot *)object
|
||||
atIndex:(NSUInteger)index {
|
||||
NSParameterAssert([object.key isKindOfClass:[NSString class]]);
|
||||
id<FUIDataObservable> query = [self.data child:object.key];
|
||||
__weak typeof(self) wSelf = self;
|
||||
FUIQueryObserver *obs = [FUIQueryObserver observerForQuery:query
|
||||
completion:^(FUIQueryObserver *observer,
|
||||
FIRDataSnapshot *snap,
|
||||
NSError *error) {
|
||||
[wSelf observer:observer didFinishLoadWithSnap:snap error:error];
|
||||
}];
|
||||
[self.observers insertObject:obs atIndex:index];
|
||||
|
||||
if ([self.delegate respondsToSelector:@selector(array:didAddReference:atIndex:)]) {
|
||||
[self.delegate array:self didAddReference:query atIndex:index];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)array:(FUIArray *)array
|
||||
didMoveObject:(FIRDataSnapshot *)object
|
||||
fromIndex:(NSUInteger)fromIndex
|
||||
toIndex:(NSUInteger)toIndex {
|
||||
NSParameterAssert([object.key isKindOfClass:[NSString class]]);
|
||||
FUIQueryObserver *obs = self.observers[fromIndex];
|
||||
|
||||
[self.observers removeObjectAtIndex:fromIndex];
|
||||
[self.observers insertObject:obs atIndex:toIndex];
|
||||
|
||||
if ([self.delegate respondsToSelector:@selector(array:didMoveReference:fromIndex:toIndex:)]) {
|
||||
[self.delegate array:self didMoveReference:obs.query fromIndex:fromIndex toIndex:toIndex];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)array:(FUIArray *)array
|
||||
didChangeObject:(FIRDataSnapshot *)object
|
||||
atIndex:(NSUInteger)index {
|
||||
NSParameterAssert([object.key isKindOfClass:[NSString class]]);
|
||||
|
||||
// Cancel any active loads on the old observer
|
||||
[self.observers[index] removeAllObservers];
|
||||
|
||||
// Add new observer
|
||||
__weak typeof(self) wSelf = self;
|
||||
id<FUIDataObservable> query = [self.data child:object.key];
|
||||
FUIQueryObserver *obs = [FUIQueryObserver observerForQuery:query
|
||||
completion:^(FUIQueryObserver *observer,
|
||||
FIRDataSnapshot *snap,
|
||||
NSError *error) {
|
||||
[wSelf observer:observer didFinishLoadWithSnap:snap error:error];
|
||||
}];
|
||||
[self.observers replaceObjectAtIndex:index withObject:obs];
|
||||
|
||||
if ([self.delegate respondsToSelector:@selector(array:didChangeReference:atIndex:)]) {
|
||||
[self.delegate array:self didChangeReference:query atIndex:index];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)array:(FUIArray *)array
|
||||
didRemoveObject:(FIRDataSnapshot *)object
|
||||
atIndex:(NSUInteger)index {
|
||||
// Cancel loads on old observer
|
||||
[self.observers[index] removeAllObservers];
|
||||
|
||||
[self.observers removeObjectAtIndex:index];
|
||||
|
||||
id<FUIDataObservable> query = [self.data child:object.key];
|
||||
if ([self.delegate respondsToSelector:@selector(array:didRemoveReference:atIndex:)]) {
|
||||
[self.delegate array:self didRemoveReference:query atIndex:index];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)array:(FUIArray *)array queryCancelledWithError:(NSError *)error {
|
||||
[self invalidate];
|
||||
if ([self.delegate respondsToSelector:@selector(array:queryCancelledWithError:)]) {
|
||||
[self.delegate array:self queryCancelledWithError:error];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#import "FirebaseDatabaseUI/Sources/Public/FirebaseDatabaseUI/FUIIndexCollectionViewDataSource.h"
|
||||
|
||||
#import "FirebaseDatabaseUI/Sources/Public/FirebaseDatabaseUI/FUIIndexArray.h"
|
||||
|
||||
@interface FUIIndexCollectionViewDataSource () <FUIIndexArrayDelegate>
|
||||
|
||||
@property (nonatomic, readonly, nonnull) FUIIndexArray *array;
|
||||
@property (nonatomic, weak, nullable) UICollectionView *collectionView;
|
||||
|
||||
@property (nonatomic, readonly, copy) UICollectionViewCell *(^populateCell)
|
||||
(UICollectionView *collectionView, NSIndexPath *indexPath, FIRDataSnapshot *object);
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUIIndexCollectionViewDataSource
|
||||
|
||||
- (instancetype)initWithIndex:(FIRDatabaseQuery *)indexQuery
|
||||
data:(FIRDatabaseReference *)dataQuery
|
||||
delegate:(id<FUIIndexCollectionViewDataSourceDelegate>)delegate
|
||||
populateCell:(UICollectionViewCell *(^)(UICollectionView *collectionView,
|
||||
NSIndexPath *indexPath,
|
||||
FIRDataSnapshot *snap))populateCell {
|
||||
FUIIndexArray *array = [[FUIIndexArray alloc] initWithIndex:indexQuery
|
||||
data:dataQuery
|
||||
delegate:self];
|
||||
return [self initWithIndexArray:array delegate:delegate populateCell:populateCell];
|
||||
}
|
||||
|
||||
- (instancetype)initWithIndexArray:(FUIIndexArray *)indexArray
|
||||
delegate:(id<FUIIndexCollectionViewDataSourceDelegate>)delegate
|
||||
populateCell:(UICollectionViewCell *(^)(UICollectionView *collectionView,
|
||||
NSIndexPath *indexPath,
|
||||
FIRDataSnapshot *snap))populateCell {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_array = indexArray;
|
||||
_collectionView.dataSource = self;
|
||||
_populateCell = populateCell;
|
||||
_delegate = delegate;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSArray<FIRDataSnapshot *> *)indexes {
|
||||
return self.array.indexes;
|
||||
}
|
||||
|
||||
- (FIRDataSnapshot *)snapshotAtIndex:(NSInteger)index {
|
||||
return [self.array objectAtIndex:index];
|
||||
}
|
||||
|
||||
- (void)bindToView:(UICollectionView *)view {
|
||||
self.collectionView = view;
|
||||
view.dataSource = self;
|
||||
[self.array observeQuery];
|
||||
}
|
||||
|
||||
- (void)unbind {
|
||||
[self.array invalidate];
|
||||
self.collectionView.dataSource = nil;
|
||||
self.collectionView = nil;
|
||||
}
|
||||
|
||||
#pragma mark - FUIIndexArrayDelegate
|
||||
|
||||
- (void)array:(FUIIndexArray *)array
|
||||
reference:(FIRDatabaseReference *)ref
|
||||
atIndex:(NSUInteger)index
|
||||
didFailLoadWithError:(NSError *)error {
|
||||
if ([self.delegate respondsToSelector:@selector(dataSource:reference:didFailLoadAtIndex:withError:)]) {
|
||||
[self.delegate dataSource:self reference:ref didFailLoadAtIndex:index withError:error];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)array:(FUIIndexArray *)array queryCancelledWithError:(NSError *)error {
|
||||
if ([self.delegate respondsToSelector:@selector(dataSource:indexQueryDidFailWithError:)]) {
|
||||
[self.delegate dataSource:self indexQueryDidFailWithError:error];
|
||||
}
|
||||
NSLog(@"%@ Error: Firebase query cancelled with error %@", self, error);
|
||||
}
|
||||
|
||||
- (void)array:(FUIIndexArray *)array
|
||||
didAddReference:(FIRDatabaseReference *)ref
|
||||
atIndex:(NSUInteger)index {
|
||||
[self.collectionView
|
||||
insertItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:index inSection:0] ]];
|
||||
}
|
||||
|
||||
- (void)array:(FUIIndexArray *)array
|
||||
didChangeReference:(FIRDatabaseReference *)ref
|
||||
atIndex:(NSUInteger)index {
|
||||
[self.collectionView
|
||||
reloadItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:index inSection:0] ]];
|
||||
}
|
||||
|
||||
- (void)array:(FUIIndexArray *)array
|
||||
didRemoveReference:(FIRDatabaseReference *)ref
|
||||
atIndex:(NSUInteger)index {
|
||||
[self.collectionView
|
||||
deleteItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:index inSection:0] ]];
|
||||
}
|
||||
|
||||
- (void)array:(FUIIndexArray *)array
|
||||
didMoveReference:(FIRDatabaseReference *)ref
|
||||
fromIndex:(NSUInteger)fromIndex
|
||||
toIndex:(NSUInteger)toIndex {
|
||||
[self.collectionView moveItemAtIndexPath:[NSIndexPath indexPathForItem:fromIndex inSection:0]
|
||||
toIndexPath:[NSIndexPath indexPathForItem:toIndex inSection:0]];
|
||||
}
|
||||
|
||||
- (void)array:(FUIIndexArray *)array
|
||||
reference:(FIRDatabaseReference *)ref
|
||||
didLoadObject:(FIRDataSnapshot *)object
|
||||
atIndex:(NSUInteger)index {
|
||||
NSIndexPath *path = [NSIndexPath indexPathForRow:index inSection:0];
|
||||
[self.collectionView reloadItemsAtIndexPaths:@[path]];
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDataSource
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView
|
||||
numberOfItemsInSection:(NSInteger)section {
|
||||
return self.array.count;
|
||||
}
|
||||
|
||||
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
|
||||
cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
FIRDataSnapshot *snap = [self.array objectAtIndex:indexPath.item];
|
||||
UICollectionViewCell *cell = self.populateCell(collectionView, indexPath, snap);
|
||||
return cell;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation UICollectionView (FUIIndexCollectionViewDataSource)
|
||||
|
||||
- (FUIIndexCollectionViewDataSource *)bindToIndexedQuery:(FIRDatabaseQuery *)index
|
||||
data:(FIRDatabaseReference *)data
|
||||
delegate:(id<FUIIndexCollectionViewDataSourceDelegate>)delegate
|
||||
populateCell:(UICollectionViewCell *(^)(UICollectionView *,
|
||||
NSIndexPath *,
|
||||
FIRDataSnapshot *))populateCell {
|
||||
FUIIndexCollectionViewDataSource *dataSource =
|
||||
[[FUIIndexCollectionViewDataSource alloc] initWithIndex:index
|
||||
data:data
|
||||
delegate:delegate
|
||||
populateCell:populateCell];
|
||||
[dataSource bindToView:self];
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
@end
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#import "FirebaseDatabaseUI/Sources/Public/FirebaseDatabaseUI/FUIIndexTableViewDataSource.h"
|
||||
|
||||
#import "FirebaseDatabaseUI/Sources/Public/FirebaseDatabaseUI/FUIIndexArray.h"
|
||||
|
||||
@interface FUIIndexTableViewDataSource () <FUIIndexArrayDelegate>
|
||||
|
||||
@property (nonatomic, readonly, nonnull) FUIIndexArray *array;
|
||||
@property (nonatomic, weak, nullable) UITableView *tableView;
|
||||
|
||||
@property (nonatomic, readonly, copy) UITableViewCell *(^populateCell)
|
||||
(UITableView *tableView, NSIndexPath *indexPath, FIRDataSnapshot *snap);
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUIIndexTableViewDataSource
|
||||
|
||||
- (instancetype)init {
|
||||
NSException *e =
|
||||
[NSException exceptionWithName:@"FIRUnavailableMethodException"
|
||||
reason:@"-init is unavailable. Please use the designated initializer instead."
|
||||
userInfo:nil];
|
||||
@throw e;
|
||||
}
|
||||
|
||||
- (instancetype)initWithIndexArray:(FUIIndexArray *)indexArray
|
||||
delegate:(nullable id<FUIIndexTableViewDataSourceDelegate>)delegate
|
||||
populateCell:(UITableViewCell *(^)(UITableView *tableView,
|
||||
NSIndexPath *indexPath,
|
||||
FIRDataSnapshot *snap))populateCell {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_array = indexArray;
|
||||
_populateCell = populateCell;
|
||||
_delegate = delegate;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithIndex:(FIRDatabaseQuery *)indexQuery
|
||||
data:(FIRDatabaseReference *)dataQuery
|
||||
delegate:(nullable id<FUIIndexTableViewDataSourceDelegate>)delegate
|
||||
populateCell:(UITableViewCell *(^)(UITableView *tableView,
|
||||
NSIndexPath *indexPath,
|
||||
FIRDataSnapshot *snap))populateCell {
|
||||
FUIIndexArray *array = [[FUIIndexArray alloc] initWithIndex:indexQuery
|
||||
data:dataQuery
|
||||
delegate:self];
|
||||
return [self initWithIndexArray:array delegate:delegate populateCell:populateCell];
|
||||
}
|
||||
|
||||
- (NSArray<FIRDataSnapshot *> *)indexes {
|
||||
return self.array.indexes;
|
||||
}
|
||||
|
||||
- (FIRDataSnapshot *)snapshotAtIndex:(NSInteger)index {
|
||||
return [self.array objectAtIndex:index];
|
||||
}
|
||||
|
||||
- (void)bindToView:(UITableView *)view {
|
||||
self.tableView = view;
|
||||
view.dataSource = self;
|
||||
[self.array observeQuery];
|
||||
}
|
||||
|
||||
- (void)unbind {
|
||||
[self.array invalidate];
|
||||
self.tableView.dataSource = nil;
|
||||
self.tableView = nil;
|
||||
}
|
||||
|
||||
#pragma mark - FUIIndexArrayDelegate
|
||||
|
||||
- (void)array:(FUIIndexArray *)array
|
||||
reference:(FIRDatabaseReference *)ref
|
||||
atIndex:(NSUInteger)index
|
||||
didFailLoadWithError:(NSError *)error {
|
||||
if ([self.delegate respondsToSelector:@selector(dataSource:reference:didFailLoadAtIndex:withError:)]) {
|
||||
[self.delegate dataSource:self reference:ref didFailLoadAtIndex:index withError:error];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)array:(FUIIndexArray *)array queryCancelledWithError:(NSError *)error {
|
||||
if ([self.delegate respondsToSelector:@selector(dataSource:indexQueryDidFailWithError:)]) {
|
||||
[self.delegate dataSource:self indexQueryDidFailWithError:error];
|
||||
}
|
||||
NSLog(@"%@ Error: Firebase query cancelled with error %@", self, error);
|
||||
}
|
||||
|
||||
- (void)array:(FUIIndexArray *)array
|
||||
didAddReference:(FIRDatabaseReference *)ref
|
||||
atIndex:(NSUInteger)index {
|
||||
[self.tableView beginUpdates];
|
||||
[self.tableView insertRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:index inSection:0] ]
|
||||
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
[self.tableView endUpdates];
|
||||
}
|
||||
|
||||
- (void)array:(FUIIndexArray *)array
|
||||
didChangeReference:(FIRDatabaseReference *)ref
|
||||
atIndex:(NSUInteger)index {
|
||||
[self.tableView beginUpdates];
|
||||
[self.tableView reloadRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:index inSection:0] ]
|
||||
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
[self.tableView endUpdates];
|
||||
}
|
||||
|
||||
- (void)array:(FUIIndexArray *)array
|
||||
didRemoveReference:(FIRDatabaseReference *)ref
|
||||
atIndex:(NSUInteger)index {
|
||||
[self.tableView beginUpdates];
|
||||
[self.tableView deleteRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:index inSection:0] ]
|
||||
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
[self.tableView endUpdates];
|
||||
}
|
||||
|
||||
- (void)array:(FUIIndexArray *)array
|
||||
didMoveReference:(FIRDatabaseReference *)ref
|
||||
fromIndex:(NSUInteger)fromIndex
|
||||
toIndex:(NSUInteger)toIndex {
|
||||
[self.tableView beginUpdates];
|
||||
[self.tableView moveRowAtIndexPath:[NSIndexPath indexPathForRow:fromIndex inSection:0]
|
||||
toIndexPath:[NSIndexPath indexPathForRow:toIndex inSection:0]];
|
||||
[self.tableView endUpdates];
|
||||
}
|
||||
|
||||
- (void)array:(FUIIndexArray *)array
|
||||
reference:(FIRDatabaseReference *)ref
|
||||
didLoadObject:(FIRDataSnapshot *)object
|
||||
atIndex:(NSUInteger)index {
|
||||
NSIndexPath *path = [NSIndexPath indexPathForRow:index inSection:0];
|
||||
[self.tableView reloadRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDataSource
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView
|
||||
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
FIRDataSnapshot *snap = [self.array objectAtIndex:indexPath.row];
|
||||
UITableViewCell *cell = self.populateCell(tableView, indexPath, snap);
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return self.array.count;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation UITableView (FUIIndexTableViewDataSource)
|
||||
|
||||
- (FUIIndexTableViewDataSource *)bindToIndexedQuery:(FIRDatabaseQuery *)index
|
||||
data:(FIRDatabaseReference *)data
|
||||
delegate:(id<FUIIndexTableViewDataSourceDelegate>)delegate
|
||||
populateCell:(UITableViewCell *(^)(UITableView *,
|
||||
NSIndexPath *,
|
||||
FIRDataSnapshot *))populateCell {
|
||||
FUIIndexTableViewDataSource *dataSource =
|
||||
[[FUIIndexTableViewDataSource alloc] initWithIndex:index
|
||||
data:data
|
||||
delegate:delegate
|
||||
populateCell:populateCell];
|
||||
[dataSource bindToView:self];
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,97 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#import "FirebaseDatabaseUI/Sources/Public/FirebaseDatabaseUI/FUIQueryObserver.h"
|
||||
|
||||
@interface FUIQueryObserver ()
|
||||
|
||||
@property (nonatomic, readonly) NSMutableSet<NSNumber *> *handles;
|
||||
@property (nonatomic, readwrite) FIRDataSnapshot *contents;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUIQueryObserver
|
||||
|
||||
- (instancetype)init {
|
||||
self = [self initWithQuery:(id _Nonnull)nil]; // silence a clang warning
|
||||
__unused id value = self; // silence an analyzer warning
|
||||
NSException *e =
|
||||
[NSException exceptionWithName:@"FIRUnavailableMethodException"
|
||||
reason:@"-init is unavailable. Please use the designated initializer instead."
|
||||
userInfo:nil];
|
||||
@throw e;
|
||||
}
|
||||
|
||||
- (instancetype)initWithQuery:(id<FUIDataObservable>)query {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_query = query;
|
||||
_handles = [NSMutableSet setWithCapacity:4];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (FUIQueryObserver *)observerForQuery:(id<FUIDataObservable>)query
|
||||
completion:(void (^)(FUIQueryObserver *obs,
|
||||
FIRDataSnapshot *snap,
|
||||
NSError *error))completion {
|
||||
FUIQueryObserver *obs = [[FUIQueryObserver alloc] initWithQuery:query];
|
||||
|
||||
void (^observerBlock)(FIRDataSnapshot *, NSString *) = ^(FIRDataSnapshot *snap,
|
||||
NSString *previous) {
|
||||
obs.contents = snap;
|
||||
completion(obs, snap, nil);
|
||||
};
|
||||
void (^cancelBlock)(NSError *) = ^(NSError *error) {
|
||||
completion(obs, nil, error);
|
||||
};
|
||||
|
||||
[obs observeEventType:FIRDataEventTypeValue
|
||||
andPreviousSiblingKeyWithBlock:observerBlock withCancelBlock:cancelBlock];
|
||||
return obs;
|
||||
}
|
||||
|
||||
- (void)observeEventType:(FIRDataEventType)eventType
|
||||
andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block
|
||||
withCancelBlock:(nullable void (^)(NSError* error))cancelBlock {
|
||||
FIRDatabaseHandle observerHandle = [self.query observeEventType:eventType
|
||||
andPreviousSiblingKeyWithBlock:block
|
||||
withCancelBlock:cancelBlock];
|
||||
NSNumber *handle = @(observerHandle);
|
||||
if ([self.handles containsObject:handle]) {
|
||||
[self.query removeObserverWithHandle:handle.unsignedIntegerValue];
|
||||
}
|
||||
|
||||
[self.handles addObject:handle];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self removeAllObservers];
|
||||
}
|
||||
|
||||
- (void)removeAllObservers {
|
||||
for (NSNumber *handle in _handles) {
|
||||
[_query removeObserverWithHandle:handle.unsignedIntegerValue];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object {
|
||||
if (![object isKindOfClass:[self class]]) { return NO; }
|
||||
FUIQueryObserver *obs = object;
|
||||
return [self.query isEqual:obs.query];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,174 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#import "FirebaseDatabaseUI/Sources/Public/FirebaseDatabaseUI/FUISortedArray.h"
|
||||
|
||||
@interface FUISortedArray ()
|
||||
|
||||
/**
|
||||
* A closure used to sort the downloaded contents from the Firebase query.
|
||||
*/
|
||||
@property (nonatomic, copy, nonnull) NSComparisonResult (^sortDescriptor)(FIRDataSnapshot *, FIRDataSnapshot *);
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUISortedArray
|
||||
// Cheating at subclassing, but this @dynamic avoids
|
||||
// duplicating storage without exposing mutability publicly
|
||||
@dynamic snapshots, handles;
|
||||
|
||||
- (instancetype)initWithQuery:(FIRDatabaseQuery *)query
|
||||
delegate:(id<FUICollectionDelegate>)delegate
|
||||
sortDescriptor:(NSComparisonResult (^)(FIRDataSnapshot *,
|
||||
FIRDataSnapshot *))sortDescriptor {
|
||||
self = [super initWithQuery:query delegate:delegate];
|
||||
if (self != nil) {
|
||||
_sortDescriptor = sortDescriptor;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)insertSnapshot:(FIRDataSnapshot *)snap withPreviousChildKey:(NSString *)previous {
|
||||
NSInteger index = [self insertSnapshot:snap];
|
||||
if ([self.delegate respondsToSelector:@selector(array:didAddObject:atIndex:)]) {
|
||||
[self.delegate array:self didAddObject:snap atIndex:index];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeSnapshot:(FIRDataSnapshot *)snap withPreviousChildKey:(NSString *)previous {
|
||||
NSInteger index = [self indexForKey:snap.key];
|
||||
if (index == NSNotFound) { /* error */ return; }
|
||||
|
||||
[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 {
|
||||
// Remove and re-insert to maintain sortedness. There are faster ways
|
||||
// to do this but idgaf
|
||||
NSInteger index = [self indexForKey:snap.key];
|
||||
if (index == NSNotFound) { /* error */ return; }
|
||||
|
||||
// Since changes can change ordering, model changes as a deletion and an insertion.
|
||||
FIRDataSnapshot *removed = [self snapshotAtIndex:index];
|
||||
[self.snapshots removeObjectAtIndex:index];
|
||||
[self.keys removeObjectAtIndex:index];
|
||||
if ([self.delegate respondsToSelector:@selector(array:didRemoveObject:atIndex:)]) {
|
||||
[self.delegate array:self didRemoveObject:removed atIndex:index];
|
||||
}
|
||||
|
||||
NSInteger newIndex = [self insertSnapshot:snap];
|
||||
if ([self.delegate respondsToSelector:@selector(array:didAddObject:atIndex:)]) {
|
||||
[self.delegate array:self didAddObject:snap atIndex:newIndex];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)moveSnapshot:(FIRDataSnapshot *)snap withPreviousChildKey:(NSString *)previous {
|
||||
// Ignore this event, since we do our own ordering.
|
||||
}
|
||||
|
||||
- (NSArray *)items {
|
||||
return super.items;
|
||||
}
|
||||
|
||||
- (NSInteger)insertSnapshot:(FIRDataSnapshot *)snapshot {
|
||||
if (self.count == 0) {
|
||||
[self.snapshots addObject:snapshot];
|
||||
[self.keys addObject:snapshot.key];
|
||||
return 0;
|
||||
}
|
||||
if (self.count == 1) {
|
||||
NSComparisonResult result = self.sortDescriptor(snapshot, [self snapshotAtIndex:0]);
|
||||
switch (result) {
|
||||
case NSOrderedDescending:
|
||||
[self.snapshots addObject:snapshot];
|
||||
[self.keys addObject:snapshot.key];
|
||||
return 1;
|
||||
default:
|
||||
[self.snapshots insertObject:snapshot atIndex:0];
|
||||
[self.keys insertObject:snapshot.key atIndex:0];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
NSInteger lowerBound = 0;
|
||||
NSInteger upperBound = self.snapshots.count;
|
||||
NSInteger index = self.count / 2;
|
||||
while (index >= 0 && index <= upperBound) {
|
||||
|
||||
if (index == 0) {
|
||||
[self.snapshots insertObject:snapshot atIndex:0];
|
||||
[self.keys insertObject:snapshot.key atIndex:0];
|
||||
return 0;
|
||||
}
|
||||
if (index == self.snapshots.count) {
|
||||
[self.snapshots addObject:snapshot];
|
||||
[self.keys addObject:snapshot.key];
|
||||
return index;
|
||||
}
|
||||
|
||||
// Comparison results are as if the item were to be inserted between the two
|
||||
// compared objects.
|
||||
NSComparisonResult left = self.sortDescriptor([self snapshotAtIndex:index - 1], snapshot);
|
||||
NSComparisonResult right = self.sortDescriptor(snapshot, [self snapshotAtIndex:index]);
|
||||
|
||||
if (left == NSOrderedDescending && right == NSOrderedAscending) {
|
||||
// look left
|
||||
upperBound = index;
|
||||
index = (lowerBound + upperBound) / 2;
|
||||
continue;
|
||||
} else if (left == NSOrderedAscending && right == NSOrderedDescending) {
|
||||
// look right
|
||||
lowerBound = index + 1;
|
||||
index = (lowerBound + upperBound) / 2;
|
||||
continue;
|
||||
} else if (left == NSOrderedDescending && right == NSOrderedDescending) {
|
||||
// bad state (array is not sorted to begin with)
|
||||
NSAssert(NO, @"FUISortedArray %@'s sort descriptor returned inconsistent results!", self);
|
||||
} else {
|
||||
// good
|
||||
[self.snapshots insertObject:snapshot atIndex:index];
|
||||
[self.keys insertObject:snapshot.key atIndex:index];
|
||||
return index;
|
||||
}
|
||||
}
|
||||
// should be unreachable, but compiler has no way of knowing array is
|
||||
// always supposed to be sorted.
|
||||
NSAssert(NO, @"Failed to insert new snapshot: Either sortDescriptor returned inconsistent "
|
||||
@"results or this is a bug in FirebaseUI");
|
||||
abort();
|
||||
}
|
||||
|
||||
@end
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
// 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 "FirebaseDatabaseUI/Sources/Public/FirebaseDatabaseUI/FUIArray.h"
|
||||
#import "FirebaseDatabaseUI/Sources/Public/FirebaseDatabaseUI/FUITableViewDataSource.h"
|
||||
|
||||
@interface FUITableViewDataSource () <FUICollectionDelegate>
|
||||
|
||||
@property (strong, nonatomic, readwrite) UITableViewCell *(^populateCell)
|
||||
(UITableView *tableView, NSIndexPath *indexPath, FIRDataSnapshot *snap);
|
||||
|
||||
@property (strong, nonatomic, readonly) id<FUICollection> collection;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUITableViewDataSource
|
||||
|
||||
#pragma mark - FUIDataSource initializer methods
|
||||
|
||||
- (instancetype)initWithCollection:(id<FUICollection>)collection
|
||||
populateCell:(UITableViewCell *(^)(UITableView *,
|
||||
NSIndexPath *,
|
||||
FIRDataSnapshot *))populateCell {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_collection = collection;
|
||||
_collection.delegate = self;
|
||||
_populateCell = populateCell;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithQuery:(FIRDatabaseQuery *)query
|
||||
populateCell:(UITableViewCell *(^)(UITableView *,
|
||||
NSIndexPath *,
|
||||
FIRDataSnapshot *))populateCell {
|
||||
FUIArray *array = [[FUIArray alloc] initWithQuery:query];
|
||||
return [self initWithCollection:array populateCell:populateCell];
|
||||
}
|
||||
|
||||
- (NSUInteger)count {
|
||||
return self.collection.count;
|
||||
}
|
||||
|
||||
- (NSArray<FIRDataSnapshot *> *)items {
|
||||
return self.collection.items;
|
||||
}
|
||||
|
||||
- (FIRDataSnapshot *)snapshotAtIndex:(NSInteger)index {
|
||||
return [self.collection snapshotAtIndex:index];
|
||||
}
|
||||
|
||||
- (void)bindToView:(UITableView *)view {
|
||||
self.tableView = view;
|
||||
view.dataSource = self;
|
||||
[self.collection observeQuery];
|
||||
}
|
||||
|
||||
- (void)unbind {
|
||||
self.tableView.dataSource = nil;
|
||||
self.tableView = nil;
|
||||
[self.collection invalidate];
|
||||
}
|
||||
|
||||
#pragma mark - FUICollectionDelegate methods
|
||||
|
||||
- (void)arrayDidBeginUpdates:(id<FUICollection>)collection {
|
||||
}
|
||||
|
||||
- (void)arrayDidEndUpdates:(id<FUICollection>)collection {
|
||||
}
|
||||
|
||||
- (void)array:(FUIArray *)array didAddObject:(id)object atIndex:(NSUInteger)index {
|
||||
[self.tableView insertRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:index inSection:0] ]
|
||||
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
}
|
||||
|
||||
- (void)array:(FUIArray *)array didChangeObject:(id)object atIndex:(NSUInteger)index {
|
||||
[self.tableView reloadRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:index inSection:0] ]
|
||||
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
}
|
||||
|
||||
- (void)array:(FUIArray *)array didRemoveObject:(id)object atIndex:(NSUInteger)index {
|
||||
[self.tableView deleteRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:index inSection:0] ]
|
||||
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
}
|
||||
|
||||
- (void)array:(FUIArray *)array didMoveObject:(id)object
|
||||
fromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex {
|
||||
[self.tableView moveRowAtIndexPath:[NSIndexPath indexPathForRow:fromIndex inSection:0]
|
||||
toIndexPath:[NSIndexPath indexPathForRow:toIndex inSection:0]];
|
||||
}
|
||||
|
||||
- (void)array:(id<FUICollection>)array queryCancelledWithError:(NSError *)error {
|
||||
if (self.queryErrorHandler != NULL) {
|
||||
self.queryErrorHandler(error);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDataSource methods
|
||||
|
||||
- (id)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
FIRDataSnapshot *snap = [self.collection.items objectAtIndex:indexPath.row];
|
||||
|
||||
UITableViewCell *cell = self.populateCell(tableView, indexPath, snap);
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return self.collection.count;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation UITableView (FUITableViewDataSource)
|
||||
|
||||
- (FUITableViewDataSource *)bindToQuery:(FIRDatabaseQuery *)query
|
||||
populateCell:(UITableViewCell *(^)(UITableView *tableView,
|
||||
NSIndexPath *indexPath,
|
||||
FIRDataSnapshot *snap))populateCell {
|
||||
FUITableViewDataSource *dataSource =
|
||||
[[FUITableViewDataSource alloc] initWithQuery:query populateCell:populateCell];
|
||||
[dataSource bindToView:self];
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
@end
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#import <FirebaseDatabase/FirebaseDatabase.h>
|
||||
|
||||
#import "FUICollection.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol FUIDataObservable <NSObject>
|
||||
@required
|
||||
|
||||
- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType
|
||||
andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block
|
||||
withCancelBlock:(nullable void (^)(NSError* error))cancelBlock;
|
||||
|
||||
- (void)removeObserverWithHandle:(FIRDatabaseHandle)handle;
|
||||
|
||||
- (id<FUIDataObservable>)child:(NSString *)path;
|
||||
|
||||
@end
|
||||
|
||||
@interface FIRDatabaseQuery (FUIDataObservable) <FUIDataObservable>
|
||||
@end
|
||||
|
||||
/**
|
||||
* FUIArray provides an array structure that is synchronized with a Firebase reference or
|
||||
* query. It is useful for building custom data structures or sources, and provides the base for
|
||||
* FirebaseDataSource. FUIArray maintains a large amount of internal state, and most of its methods
|
||||
* are not thread-safe.
|
||||
*/
|
||||
@interface FUIArray : NSObject <FUICollection>
|
||||
|
||||
/**
|
||||
* The delegate object that array changes are surfaced to, which conforms to the
|
||||
* @c FUICollectionDelegate protocol.
|
||||
*/
|
||||
@property (weak, nonatomic, nullable) id<FUICollectionDelegate> delegate;
|
||||
|
||||
/**
|
||||
* The query on a Firebase reference that provides data to populate the array.
|
||||
*/
|
||||
@property (strong, nonatomic) id<FUIDataObservable> query;
|
||||
|
||||
/**
|
||||
* The number of objects in the array.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSUInteger count;
|
||||
|
||||
/**
|
||||
* The items currently in the array.
|
||||
*/
|
||||
@property (nonatomic, readonly, copy) NSArray *items;
|
||||
|
||||
#pragma mark - Initializer methods
|
||||
|
||||
/**
|
||||
* Initalizes an FUIArray with a Firebase query (FIRDatabaseQuery) or database reference
|
||||
* (FIRDatabaseReference).
|
||||
* @param query A query or Firebase database reference
|
||||
* @param delegate An object conforming to FirebaseArrayDelegate that should receive delegate messages.
|
||||
* @return A FirebaseArray instance
|
||||
*/
|
||||
- (instancetype)initWithQuery:(id<FUIDataObservable>)query
|
||||
delegate:(nullable id<FUICollectionDelegate>)delegate NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* Initalizes FirebaseArray with a Firebase query (FIRDatabaseQuery) or database reference
|
||||
* (FIRDatabaseReference).
|
||||
* @param query A query or Firebase database reference
|
||||
* @return A FirebaseArray instance
|
||||
*/
|
||||
- (instancetype)initWithQuery:(id<FUIDataObservable>)query;
|
||||
|
||||
/**
|
||||
* See `initWithQuery:`
|
||||
*/
|
||||
+ (instancetype)arrayWithQuery:(id<FUIDataObservable>)query;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
#pragma mark - Public API methods
|
||||
|
||||
/**
|
||||
* Returns an object at a specific index in the array.
|
||||
* @param index The index of the item to retrieve
|
||||
* @return The snapshot at the given index
|
||||
*/
|
||||
- (FIRDataSnapshot *)snapshotAtIndex:(NSInteger)index;
|
||||
|
||||
/**
|
||||
* Returns a Firebase reference for an object at a specific index in the array.
|
||||
* @param index The index of the item to retrieve a reference for
|
||||
* @return A Firebase reference for the object at the given index
|
||||
*/
|
||||
- (FIRDatabaseReference *)refForIndex:(NSUInteger)index;
|
||||
|
||||
/**
|
||||
* Support for subscripting. Resolves to objectAtIndex:
|
||||
* @param idx The index of the item to retrieve
|
||||
* @return The object at the given index
|
||||
*/
|
||||
- (id)objectAtIndexedSubscript:(NSUInteger)idx;
|
||||
|
||||
/**
|
||||
* Support for subscripting. This method is unused and trying to write directly to the
|
||||
* array using subscripting will cause an assertion failure.
|
||||
*/
|
||||
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx NS_UNAVAILABLE;
|
||||
|
||||
/**
|
||||
* Returns an index for a given object's key (that matches the object's key in the corresponding
|
||||
* Firebase reference).
|
||||
* @param key The key of the desired object
|
||||
* @return The index of the object for which the key matches or NSNotFound if the key is not found
|
||||
* @exception NSInvalidArgumentException Thrown when the `key` parameter is `nil`.
|
||||
*/
|
||||
- (NSUInteger)indexForKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
* Called when the Firebase query sends a FIRDataEventTypeChildAdded event. Override this
|
||||
* to provide custom insertion logic. Don't call this method directly.
|
||||
* @param snap The snapshot that was inserted.
|
||||
* @param previous The key of the sibling preceding the inserted snapshot.
|
||||
*/
|
||||
- (void)insertSnapshot:(FIRDataSnapshot *)snap withPreviousChildKey:(nullable NSString *)previous;
|
||||
|
||||
/**
|
||||
* Called when the Firebase query sends a FIRDataEventTypeChildRemoved event. Override this
|
||||
* to provide custom removal logic. Don't call this method directly.
|
||||
* @param snap The snapshot that was removed.
|
||||
* @param previous The key of the sibling preceding the removed snapshot.
|
||||
*/
|
||||
- (void)removeSnapshot:(FIRDataSnapshot *)snap withPreviousChildKey:(nullable NSString *)previous;
|
||||
|
||||
/**
|
||||
* Called when the Firebase query sends a FIRDataEventTypeChildChanged event. Override this
|
||||
* to provide custom on change logic. Don't call this method directly.
|
||||
* @param snap The snapshot whose value was changed.
|
||||
* @param previous The key of the sibling preceding the changed snapshot.
|
||||
*/
|
||||
- (void)changeSnapshot:(FIRDataSnapshot *)snap withPreviousChildKey:(nullable NSString *)previous;
|
||||
|
||||
/**
|
||||
* Called when the Firebase query sends a FIRDataEventTypeChildMoved event. Override this
|
||||
* to provide custom move logic. Don't call this method directly.
|
||||
* @param snap The snapshot that was moved.
|
||||
* @param previous The key of the sibling preceding the moved snapshot at its new location.
|
||||
*/
|
||||
- (void)moveSnapshot:(FIRDataSnapshot *)snap withPreviousChildKey:(nullable NSString *)previous;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
Generated
+148
@@ -0,0 +1,148 @@
|
||||
// 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 <Foundation/Foundation.h>
|
||||
|
||||
@class FIRDatabaseReference, FIRDatabaseQuery, FIRDataSnapshot;
|
||||
@protocol FUICollectionDelegate;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* A protocol representing a collection of objects from Firebase Database.
|
||||
*/
|
||||
@protocol FUICollection <NSObject>
|
||||
|
||||
@property (nonatomic, readonly, copy) NSArray<FIRDataSnapshot *> *items;
|
||||
|
||||
@property (weak, nonatomic, nullable) id<FUICollectionDelegate> delegate;
|
||||
|
||||
/**
|
||||
* The number of objects in the collection.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSUInteger count;
|
||||
|
||||
/**
|
||||
* The @c FIRDataSnapshot at the given index. May raise fatal errors
|
||||
* if the index is out of bounds. This function is expected to return
|
||||
* nonnull snapshot instances across a contiguous range of integers
|
||||
* starting at zero.
|
||||
* @param index The index of a snapshot.
|
||||
*/
|
||||
- (FIRDataSnapshot *)snapshotAtIndex:(NSInteger)index;
|
||||
|
||||
/**
|
||||
* Calling this makes the array begin observing updates from its query.
|
||||
* Before this call is made the array is inert and doesn't do anything.
|
||||
* Custom collections implementing the FUICollection protocol should
|
||||
* not send updates via FUICollectionDelegate before this method is called.
|
||||
*/
|
||||
- (void)observeQuery;
|
||||
|
||||
/**
|
||||
* Cancels all active observations. The array may be reused after this
|
||||
* is called by calling @c observeQuery again. Custom collections
|
||||
* implementing the FUICollection protocol should not send updates after
|
||||
* this method is called unless another call is made to observeQuery.
|
||||
* The collection is expected to stay reusable; balanced calls to
|
||||
* observeQuery and invalidate should not accumulate internal state in
|
||||
* a way that would render the collection unusable.
|
||||
*/
|
||||
- (void)invalidate;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* A protocol to allow instances of FUIArray to raise events through a
|
||||
* delegate. Raises all Firebase events except FIRDataEventTypeValue.
|
||||
*/
|
||||
@protocol FUICollectionDelegate<NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
/**
|
||||
* Called before any other events are sent. When implementing a custom
|
||||
* collection, this delegate method should be called immediately before the
|
||||
* first update event in a batch update.
|
||||
*/
|
||||
- (void)arrayDidBeginUpdates:(id<FUICollection>)collection;
|
||||
|
||||
/**
|
||||
* Called after all updates have finished. When implementing a custom
|
||||
* collection, this delegate method should be called immediately after the last
|
||||
* event in a batch update (i.e. after Firebase Database sends a
|
||||
* FIRDataEventTypeValue event).
|
||||
*/
|
||||
- (void)arrayDidEndUpdates:(id<FUICollection>)collection;
|
||||
|
||||
/**
|
||||
* Delegate method which is called whenever an object is added to an FUIArray.
|
||||
* On a FUIArray synchronized to a Firebase reference, this corresponds to an
|
||||
* @c FIRDataEventTypeChildAdded event being raised. When implementing a
|
||||
* custom collection, the collection should call this method immediately after
|
||||
* an item is inserted.
|
||||
* @param object The object added to the FUIArray
|
||||
* @param index The index the child was added at
|
||||
*/
|
||||
- (void)array:(id<FUICollection>)array didAddObject:(id)object atIndex:(NSUInteger)index;
|
||||
|
||||
/**
|
||||
* Delegate method which is called whenever an object is changed in an
|
||||
* FUIArray. On a FUIArray synchronized to a Firebase reference, this
|
||||
* corresponds to an @c FIRDataEventTypeChildChanged event being raised.
|
||||
* When implementing a custom collection, this method should be called
|
||||
* immediately after an item is changed in place.
|
||||
* @param object The object that changed in the FUIArray
|
||||
* @param index The index the child was changed at
|
||||
*/
|
||||
- (void)array:(id<FUICollection>)array didChangeObject:(id)object atIndex:(NSUInteger)index;
|
||||
|
||||
/**
|
||||
* Delegate method which is called whenever an object is removed from an
|
||||
* FUIArray. On a FUIArray synchronized to a Firebase reference, this
|
||||
* corresponds to an @c FIRDataEventTypeChildRemoved event being raised.
|
||||
* When implementing a custom collection, this method should be called
|
||||
* immediately after an item is removed.
|
||||
* @param object The object removed from the FUIArray
|
||||
* @param index The index the child was removed at
|
||||
*/
|
||||
- (void)array:(id<FUICollection>)array didRemoveObject:(id)object atIndex:(NSUInteger)index;
|
||||
|
||||
/**
|
||||
* Delegate method which is called whenever an object is moved within a
|
||||
* FUIArray. On a FUIArray synchronized to a Firebase reference, this
|
||||
* corresponds to an @c FIRDataEventTypeChildMoved event being raised.
|
||||
* When implementing a custom collection, this method should be called
|
||||
* immediately after an item is moved.
|
||||
* @param object The object that has moved locations in the FUIArray
|
||||
* @param fromIndex The index the child is being moved from
|
||||
* @param toIndex The index the child is being moved to
|
||||
*/
|
||||
- (void)array:(id<FUICollection>)array didMoveObject:(id)object fromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex;
|
||||
|
||||
/**
|
||||
* Delegate method which is called whenever the backing query is canceled.
|
||||
* @param error the error that was raised
|
||||
*/
|
||||
- (void)array:(id<FUICollection>)array queryCancelledWithError:(NSError *)error;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
// 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 <UIKit/UIKit.h>
|
||||
|
||||
#import "FUICollection.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* FUICollectionViewDataSource provides a class that conforms to the
|
||||
* UICollectionViewDataSource protocol which allows UICollectionViews to
|
||||
* adopt FUICollectionViewDataSource in order to provide a UICollectionView
|
||||
* synchronized to a Firebase reference or query.
|
||||
*/
|
||||
@interface FUICollectionViewDataSource : NSObject <UICollectionViewDataSource>
|
||||
|
||||
/**
|
||||
* The UICollectionView instance that operations (inserts, removals, moves,
|
||||
* etc.) are performed against. The data source does not claim ownership of
|
||||
* the collection view it populates. This collection view must be receiving data
|
||||
* from this data source otherwise data inconsistency crashes will occur.
|
||||
*/
|
||||
@property (nonatomic, readwrite, weak, nullable) UICollectionView *collectionView;
|
||||
|
||||
/**
|
||||
* The number of items in the data source.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSUInteger count;
|
||||
|
||||
/**
|
||||
* The snapshots in the data source.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSArray<FIRDataSnapshot *> *items;
|
||||
|
||||
/**
|
||||
* A closure that should be invoked when the query encounters a fatal error.
|
||||
* After this is invoked, the query is no longer valid and the data source should
|
||||
* be recreated.
|
||||
*/
|
||||
@property (nonatomic, copy, readwrite) void (^queryErrorHandler)(NSError *);
|
||||
|
||||
/**
|
||||
* Returns the snapshot at the given index. Throws an exception if the index is out of bounds.
|
||||
*/
|
||||
- (FIRDataSnapshot *)snapshotAtIndex:(NSInteger)index;
|
||||
|
||||
/**
|
||||
* Initialize an instance of FUICollectionViewDataSource that populates
|
||||
* UICollectionViewCells with FIRDataSnapshots.
|
||||
* @param collection A FUICollection that the data source uses to pull snapshots
|
||||
* from Firebase Database.
|
||||
* @param populateCell A closure used by the data source to create the cells that
|
||||
* are displayed in the collection view. This closure is retained by the data
|
||||
* source, so if you capture self in the closure and also claim ownership of the
|
||||
* data source, be sure to avoid retain cycles by capturing a weak reference to self.
|
||||
* @return An instance of FUICollectionViewDataSource that populates
|
||||
* UICollectionViewCells with FIRDataSnapshots.
|
||||
*/
|
||||
- (instancetype)initWithCollection:(id<FUICollection>)collection
|
||||
populateCell:(UICollectionViewCell *(^)(UICollectionView *collectionView,
|
||||
NSIndexPath *indexPath,
|
||||
FIRDataSnapshot *object))populateCell NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* Initialize an unsorted instance of FUICollectionViewDataSource that populates
|
||||
* UICollectionViewCells with FIRDataSnapshots.
|
||||
* @param query A Firebase query to bind the data source to.
|
||||
* @param populateCell A closure used by the data source to create the cells that
|
||||
* are displayed in the collection view. This closure is retained by the data
|
||||
* source, so if you capture self in the closure and also claim ownership of the
|
||||
* data source, be sure to avoid retain cycles by capturing a weak reference to self.
|
||||
* @return An instance of FUICollectionViewDataSource that populates
|
||||
* UICollectionViewCells with FIRDataSnapshots.
|
||||
*/
|
||||
- (instancetype)initWithQuery:(FIRDatabaseQuery *)query
|
||||
populateCell:(UICollectionViewCell *(^)(UICollectionView *collectionView,
|
||||
NSIndexPath *indexPath,
|
||||
FIRDataSnapshot *object))populateCell;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/**
|
||||
* Attaches the data source to a collection view and begins sending updates immediately.
|
||||
* @param view An instance of UICollectionView that the data source should push
|
||||
* updates to.
|
||||
*/
|
||||
- (void)bindToView:(UICollectionView *)view;
|
||||
|
||||
/**
|
||||
* Detaches the data source from a view and stops sending any updates.
|
||||
*/
|
||||
- (void)unbind;
|
||||
|
||||
@end
|
||||
|
||||
@interface UICollectionView (FUICollectionViewDataSource)
|
||||
|
||||
/**
|
||||
* Creates a data source, attaches it to the collection view, and returns it.
|
||||
* The returned data source is not retained by the collection view and must be
|
||||
* retained or it will be deallocated while still in use by the collection view.
|
||||
* @param query A Firebase database query to bind the collection view to.
|
||||
* @param populateCell A closure used by the data source to create the cells
|
||||
* displayed in the collection view. The closure is retained by the returned
|
||||
* data source.
|
||||
* @return The created data source. This value must be retained while the collection
|
||||
* view is in use.
|
||||
*/
|
||||
- (FUICollectionViewDataSource *)bindToQuery:(FIRDatabaseQuery *)query
|
||||
populateCell:(UICollectionViewCell *(^)(UICollectionView *collectionView,
|
||||
NSIndexPath *indexPath,
|
||||
FIRDataSnapshot *object))populateCell __attribute__((warn_unused_result));
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
Generated
+187
@@ -0,0 +1,187 @@
|
||||
// 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"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class FUIIndexArray;
|
||||
|
||||
/**
|
||||
* A protocol to allow instances of FUIIndexArray to raise events through a
|
||||
* delegate. Raises all Firebase events except @c FIRDataEventTypeValue.
|
||||
*/
|
||||
@protocol FUIIndexArrayDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
/**
|
||||
* Delegate method called when the database reference at an index has
|
||||
* finished loading its contents.
|
||||
* @param array The array containing the reference.
|
||||
* @param ref The reference that was loaded.
|
||||
* @param object The database reference's contents.
|
||||
* @param index The index of the reference that was loaded.
|
||||
*/
|
||||
- (void)array:(FUIIndexArray *)array
|
||||
reference:(FIRDatabaseReference *)ref
|
||||
didLoadObject:(FIRDataSnapshot *)object
|
||||
atIndex:(NSUInteger)index;
|
||||
|
||||
/**
|
||||
* Delegate method called when the database reference at an index has
|
||||
* failed to load contents.
|
||||
* @param array The array containing the reference.
|
||||
* @param ref The reference that failed to load.
|
||||
* @param index The index in the array of the reference that failed to load.
|
||||
* @param error The error that occurred.
|
||||
*/
|
||||
- (void)array:(FUIIndexArray *)array
|
||||
reference:(FIRDatabaseReference *)ref
|
||||
atIndex:(NSUInteger)index
|
||||
didFailLoadWithError:(NSError *)error;
|
||||
|
||||
/**
|
||||
* Delegate method which is called whenever an object is added to a
|
||||
* FirebaseArray. On a FirebaseArray synchronized to a Firebase reference,
|
||||
* this corresponds to a @c FIRDataEventTypeChildAdded event being raised.
|
||||
* @param ref The database reference added to the array
|
||||
* @param index The index the reference was added at
|
||||
*/
|
||||
- (void)array:(FUIIndexArray *)array didAddReference:(FIRDatabaseReference *)ref atIndex:(NSUInteger)index;
|
||||
|
||||
/**
|
||||
* Delegate method which is called whenever an object is changed in a
|
||||
* FirebaseArray. On a FirebaseArray synchronized to a Firebase reference,
|
||||
* this corresponds to a @c FIRDataEventTypeChildChanged event being raised.
|
||||
* @param ref The database reference that changed in the array
|
||||
* @param index The index the reference was changed at
|
||||
*/
|
||||
- (void)array:(FUIIndexArray *)array didChangeReference:(FIRDatabaseReference *)ref atIndex:(NSUInteger)index;
|
||||
|
||||
/**
|
||||
* Delegate method which is called whenever an object is removed from a
|
||||
* FirebaseArray. On a FirebaseArray synchronized to a Firebase reference,
|
||||
* this corresponds to a @c FIRDataEventTypeChildRemoved event being raised.
|
||||
* @param ref The database reference removed from the array
|
||||
* @param index The index the reference was removed at
|
||||
*/
|
||||
- (void)array:(FUIIndexArray *)array didRemoveReference:(FIRDatabaseReference *)ref atIndex:(NSUInteger)index;
|
||||
|
||||
/**
|
||||
* Delegate method which is called whenever an object is moved within a
|
||||
* FirebaseArray. On a FirebaseArray synchronized to a Firebase reference,
|
||||
* this corresponds to a @c FIRDataEventTypeChildMoved event being raised.
|
||||
* @param ref The database reference that has moved locations
|
||||
* @param fromIndex The index the reference is being moved from
|
||||
* @param toIndex The index the reference is being moved to
|
||||
*/
|
||||
- (void)array:(FUIIndexArray *)array didMoveReference:(FIRDatabaseReference *)ref fromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex;
|
||||
|
||||
/**
|
||||
* Delegate method which is called whenever the backing query is canceled. This error is fatal
|
||||
* and the index array will become unusable afterward, so please handle it appropriately
|
||||
* (i.e. by displaying a modal error explaining why there's no content).
|
||||
* @param error the error that was raised
|
||||
*/
|
||||
- (void)array:(FUIIndexArray *)array queryCancelledWithError:(NSError *)error;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* A FUIIndexArray instance uses a query's contents to query children of
|
||||
* a separate database reference, which is useful for displaying an indexed list
|
||||
* of data as described in https://firebase.google.com/docs/database/ios/structure-data
|
||||
*/
|
||||
@interface FUIIndexArray : NSObject
|
||||
|
||||
/**
|
||||
* An immutable copy of the loaded contents in the array. Returns an
|
||||
* empty array if no contents have loaded yet.
|
||||
*/
|
||||
@property(nonatomic, copy, readonly) NSArray<FIRDataSnapshot *> *items;
|
||||
|
||||
/**
|
||||
* An immutable copy of the loaded indexes in the array. Returns an empty
|
||||
* array if no indexes have loaded.
|
||||
*/
|
||||
@property(nonatomic, copy, readonly) NSArray<FIRDataSnapshot *> *indexes;
|
||||
|
||||
/**
|
||||
* The delegate that this array should forward events to.
|
||||
*/
|
||||
@property(nonatomic, weak) id<FUIIndexArrayDelegate> delegate;
|
||||
|
||||
/**
|
||||
* Returns the number of items in the array.
|
||||
*/
|
||||
@property(nonatomic, readonly) NSUInteger count;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/**
|
||||
* Initializes a FUIIndexArray with an index query and a data query.
|
||||
* The array expects the keys of the children of the index query to match exactly children
|
||||
* of the data query.
|
||||
* @param index A Firebase database query whose childrens' keys are all children
|
||||
* of the data query.
|
||||
* @param data A Firebase database reference whose children will be fetched and used
|
||||
* to populate the array's contents according to the index query.
|
||||
* @param delegate The delegate that events should be forwarded to.
|
||||
*/
|
||||
- (instancetype)initWithIndex:(id<FUIDataObservable>)index
|
||||
data:(id<FUIDataObservable>)data
|
||||
delegate:(nullable id<FUIIndexArrayDelegate>)delegate NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* Initializes a FUIIndexArray with an index query and a data query.
|
||||
* The array expects the keys of the children of the index query to be children
|
||||
* of the data query.
|
||||
* @param index A Firebase database query whose childrens' keys are all children
|
||||
* of the data query.
|
||||
* @param data A Firebase database reference whose children will be fetched and used
|
||||
* to populate the array's contents according to the index query.
|
||||
*/
|
||||
- (instancetype)initWithIndex:(id<FUIDataObservable>)index
|
||||
data:(id<FUIDataObservable>)data;
|
||||
|
||||
/**
|
||||
* Returns the snapshot at the given index, if it has loaded.
|
||||
* Raises a fatal error if the index is out of bounds.
|
||||
* @param index The index of the requested snapshot.
|
||||
* @return A snapshot, or nil if one has not yet been loaded.
|
||||
*/
|
||||
- (nullable FIRDataSnapshot *)objectAtIndex:(NSUInteger)index;
|
||||
|
||||
/**
|
||||
* Starts observing the index array's listeners. The indexed array will pass updates to its delegate
|
||||
* until the `invalidate` method is called.
|
||||
*/
|
||||
- (void)observeQuery;
|
||||
|
||||
/**
|
||||
* Removes all observers from all queries managed by this array and renders this array
|
||||
* unusable. Initialize a new array instead of reusing this array.
|
||||
*/
|
||||
- (void)invalidate;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#import <FirebaseDatabase/FirebaseDatabase.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class FUIIndexCollectionViewDataSource, FUIIndexArray;
|
||||
|
||||
@protocol FUIIndexCollectionViewDataSourceDelegate <NSObject>
|
||||
@optional
|
||||
|
||||
/**
|
||||
* Called when an individual reference responsible for populating one cell
|
||||
* of the collection view has raised an error. This error is unrecoverable, but
|
||||
* does not have any effect on the contents of other cells.
|
||||
* @param dataSource The FUIIndexCollectionViewDataSource raising the error.
|
||||
* @param ref The reference that failed to load.
|
||||
* @param index The index (i.e. row) of the query that failed to load.
|
||||
* @param error The error that occurred.
|
||||
*/
|
||||
- (void)dataSource:(FUIIndexCollectionViewDataSource *)dataSource
|
||||
reference:(FIRDatabaseReference *)ref
|
||||
didFailLoadAtIndex:(NSUInteger)index
|
||||
withError:(NSError *)error;
|
||||
|
||||
/**
|
||||
* Called when the index query used to initialize this data source raised an error.
|
||||
* This error is unrecoverable, and likely indicates a bad index query.
|
||||
* @param dataSource The FUIIndexCollectionViewDataSource raising the error.
|
||||
* @param error The error that occurred.
|
||||
*/
|
||||
- (void)dataSource:(FUIIndexCollectionViewDataSource *)dataSource
|
||||
indexQueryDidFailWithError:(NSError *)error;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* An object that manages a @c FUIIndexArray and uses it to populate and update
|
||||
* a collection view with a single section. The data source maintains a reference to but
|
||||
* does not claim ownership of the collection view that it updates.
|
||||
*/
|
||||
@interface FUIIndexCollectionViewDataSource : NSObject <UICollectionViewDataSource>
|
||||
|
||||
/**
|
||||
* The delegate that should receive updates from this data source. Implement this delegate
|
||||
* to handle load errors and successes.
|
||||
*/
|
||||
@property (nonatomic, readwrite, weak, nullable) id<FUIIndexCollectionViewDataSourceDelegate> delegate;
|
||||
|
||||
/**
|
||||
* The indexes that have finished loading in the data source. Returns an empty array if no indexes
|
||||
* have loaded.
|
||||
*/
|
||||
@property (nonatomic, readonly, copy) NSArray<FIRDataSnapshot *> *indexes;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/**
|
||||
* Initializes a collection view data source.
|
||||
* @param indexArray The FUIIndexArray whose contents will be displayed in the collection view.
|
||||
* @param populateCell The closure invoked when populating a UICollectionViewCell (or subclass).
|
||||
*/
|
||||
- (instancetype)initWithIndexArray:(FUIIndexArray *)indexArray
|
||||
delegate:(nullable id<FUIIndexCollectionViewDataSourceDelegate>)delegate
|
||||
populateCell:(UICollectionViewCell *(^)(UICollectionView *collectionView,
|
||||
NSIndexPath *indexPath,
|
||||
FIRDataSnapshot *_Nullable snap))populateCell
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* Initializes a collection view data source.
|
||||
* @param indexQuery The Firebase query containing children of the data query.
|
||||
* @param dataQuery The reference whose children correspond to the contents of the
|
||||
* index query. This reference's children's contents are served as the contents
|
||||
* of the collection view that adopts this data source.
|
||||
* @param populateCell The closure invoked when populating a UICollectionViewCell (or subclass).
|
||||
*/
|
||||
- (instancetype)initWithIndex:(FIRDatabaseQuery *)indexQuery
|
||||
data:(FIRDatabaseReference *)dataQuery
|
||||
delegate:(nullable id<FUIIndexCollectionViewDataSourceDelegate>)delegate
|
||||
populateCell:(UICollectionViewCell *(^)(UICollectionView *collectionView,
|
||||
NSIndexPath *indexPath,
|
||||
FIRDataSnapshot *_Nullable snap))populateCell;
|
||||
|
||||
/**
|
||||
* Returns the snapshot at the given index, if it has loaded.
|
||||
* Raises a fatal error if the index is out of bounds.
|
||||
* @param index The index of the requested snapshot.
|
||||
* @return A snapshot, or nil if one has not yet been loaded.
|
||||
*/
|
||||
- (nullable FIRDataSnapshot *)snapshotAtIndex:(NSInteger)index;
|
||||
|
||||
/**
|
||||
* Attaches the data source to a collection view and begins sending updates immediately.
|
||||
* @param view The collection view that is populated by this data source. The
|
||||
* data source pulls updates from Firebase database, so it must maintain a reference
|
||||
* to the collection view in order to update its contents as the database pushes updates.
|
||||
* The collection view is not retained by its data source.
|
||||
*/
|
||||
- (void)bindToView:(UICollectionView *)view;
|
||||
|
||||
/**
|
||||
* Detaches the data source from a view and stops sending any updates.
|
||||
*/
|
||||
- (void)unbind;
|
||||
|
||||
@end
|
||||
|
||||
@interface UICollectionView (FUIIndexCollectionViewDataSource)
|
||||
|
||||
/**
|
||||
* Creates a data source, attaches it to the collection view, and returns it.
|
||||
* The returned data source is not retained by the collection view and must be
|
||||
* retained or it will be deallocated while still in use by the collection view.
|
||||
* @param index The Firebase query containing children of the data query.
|
||||
* @param data The reference whose children correspond to the contents of the
|
||||
* index query. This reference's children's contents are served as the contents
|
||||
* of the collection view.
|
||||
* @param delegate The object that should respond to events from the data source.
|
||||
* @param populateCell A closure used by the data source to create the cells
|
||||
* displayed in the collection view. The closure is retained by the returned
|
||||
* data source.
|
||||
* @return The created data source. This value must be retained while the collection
|
||||
* view is in use.
|
||||
*/
|
||||
- (FUIIndexCollectionViewDataSource *)bindToIndexedQuery:(FIRDatabaseQuery *)index
|
||||
data:(FIRDatabaseReference *)data
|
||||
delegate:(id<FUIIndexCollectionViewDataSourceDelegate>)delegate
|
||||
populateCell:(UICollectionViewCell *(^)(UICollectionView *view,
|
||||
NSIndexPath *indexPath,
|
||||
FIRDataSnapshot *_Nullable snap))populateCell __attribute__((warn_unused_result));
|
||||
|
||||
@end
|
||||
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <FirebaseDatabase/FirebaseDatabase.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class FUIIndexTableViewDataSource, FUIIndexArray;
|
||||
|
||||
@protocol FUIIndexTableViewDataSourceDelegate <NSObject>
|
||||
@optional
|
||||
|
||||
/**
|
||||
* Called when an individual reference responsible for populating one cell
|
||||
* of the table view has raised an error. This error is unrecoverable, but
|
||||
* does not have any effect on the contents of other cells.
|
||||
* @param dataSource The FUIIndexTableViewDataSource raising the error.
|
||||
* @param ref The reference that failed to load.
|
||||
* @param index The index (i.e. row) of the query that failed to load.
|
||||
* @param error The error that occurred.
|
||||
*/
|
||||
- (void)dataSource:(FUIIndexTableViewDataSource *)dataSource
|
||||
reference:(FIRDatabaseReference *)ref
|
||||
didFailLoadAtIndex:(NSUInteger)index
|
||||
withError:(NSError *)error;
|
||||
|
||||
/**
|
||||
* Called when the index query used to initialize this data source raised an error.
|
||||
* This error is unrecoverable, and likely indicates a bad index query.
|
||||
* @param dataSource The FUIIndexTableViewDataSource raising the error.
|
||||
* @param error The error that occurred.
|
||||
*/
|
||||
- (void)dataSource:(FUIIndexTableViewDataSource *)dataSource
|
||||
indexQueryDidFailWithError:(NSError *)error;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* An object that manages a @c FUIIndexArray and uses it to populate and update
|
||||
* a table view with a single section. The data source maintains a reference to but
|
||||
* does not claim ownership of the table view that it updates.
|
||||
*/
|
||||
@interface FUIIndexTableViewDataSource : NSObject <UITableViewDataSource>
|
||||
|
||||
/**
|
||||
* The delegate that should receive updates from this data source. Implement this delegate
|
||||
* to handle load errors and successes.
|
||||
*/
|
||||
@property (nonatomic, readwrite, weak, nullable) id<FUIIndexTableViewDataSourceDelegate> delegate;
|
||||
|
||||
/**
|
||||
* The indexes that have finished loading in the data source. Returns an empty array if no indexes
|
||||
* have loaded.
|
||||
*/
|
||||
@property (nonatomic, readonly, copy) NSArray<FIRDataSnapshot *> *indexes;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/**
|
||||
* Initializes a table view data source.
|
||||
* @param indexQuery The Firebase query containing children of the data query.
|
||||
* @param dataQuery The reference whose children correspond to the contents of the
|
||||
* index query. This reference's children's contents are served as the contents
|
||||
* of the table view that adopts this data source.
|
||||
* @param populateCell The closure invoked when populating a UITableViewCell (or subclass).
|
||||
*/
|
||||
- (instancetype)initWithIndex:(FIRDatabaseQuery *)indexQuery
|
||||
data:(FIRDatabaseReference *)dataQuery
|
||||
delegate:(nullable id<FUIIndexTableViewDataSourceDelegate>)delegate
|
||||
populateCell:(UITableViewCell *(^)(UITableView *tableView,
|
||||
NSIndexPath *indexPath,
|
||||
FIRDataSnapshot *_Nullable snap))populateCell;
|
||||
|
||||
/**
|
||||
* Initializes a table view data source.
|
||||
* @param indexArray The FUIIndexArray whose contents will be displayed in the table view.
|
||||
* @param populateCell The closure invoked when populating a UITableViewCell (or subclass).
|
||||
*/
|
||||
- (instancetype)initWithIndexArray:(FUIIndexArray *)indexArray
|
||||
delegate:(nullable id<FUIIndexTableViewDataSourceDelegate>)delegate
|
||||
populateCell:(UITableViewCell *(^)(UITableView *tableView,
|
||||
NSIndexPath *indexPath,
|
||||
FIRDataSnapshot *_Nullable snap))populateCell
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* Returns the snapshot at the given index, if it has loaded.
|
||||
* Raises a fatal error if the index is out of bounds.
|
||||
* @param index The index of the requested snapshot.
|
||||
* @return A snapshot, or nil if one has not yet been loaded.
|
||||
*/
|
||||
- (nullable FIRDataSnapshot *)snapshotAtIndex:(NSInteger)index;
|
||||
|
||||
/**
|
||||
* Attaches the data source to a table view and begins sending updates immediately.
|
||||
* @param view The table view that is populated by this data source. The
|
||||
* data source pulls updates from Firebase database, so it must maintain a reference
|
||||
* to the table view in order to update its contents as the database pushes updates.
|
||||
* The table view is not retained by its data source.
|
||||
*/
|
||||
- (void)bindToView:(UITableView *)view;
|
||||
|
||||
/**
|
||||
* Detaches the data source from a view and stops sending any updates.
|
||||
*/
|
||||
- (void)unbind;
|
||||
|
||||
@end
|
||||
|
||||
@interface UITableView (FUIIndexTableViewDataSource)
|
||||
|
||||
/**
|
||||
* Creates a data source, attaches it to the table view, and returns it.
|
||||
* The returned data source is not retained by the table view and must be
|
||||
* retained or it will be deallocated while still in use by the table view.
|
||||
* @param index A Firebase database query to bind the table view to.
|
||||
* @param data The reference whose children correspond to the contents of the
|
||||
* index query. This reference's children's contents are served as the contents
|
||||
* of the table view.
|
||||
* @param delegate The object that should respond to events from the data source.
|
||||
* @param populateCell A closure used by the data source to create the cells
|
||||
* displayed in the table view. The closure is retained by the returned
|
||||
* data source.
|
||||
* @return The created data source. This value must be retained while the table
|
||||
* view is in use.
|
||||
*/
|
||||
- (FUIIndexTableViewDataSource *)bindToIndexedQuery:(FIRDatabaseQuery *)index
|
||||
data:(FIRDatabaseReference *)data
|
||||
delegate:(id<FUIIndexTableViewDataSourceDelegate>)delegate
|
||||
populateCell:(UITableViewCell *(^)(UITableView *view,
|
||||
NSIndexPath *indexPath,
|
||||
FIRDataSnapshot *_Nullable snap))populateCell __attribute__((warn_unused_result));
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
Generated
+53
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#import "FUIIndexArray.h"
|
||||
|
||||
/**
|
||||
* An internal helper class used by FUIIndexArray to manage all its queries.
|
||||
*/
|
||||
@interface FUIQueryObserver : NSObject
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// The query observed by this observer.
|
||||
@property (nonatomic, readonly) id<FUIDataObservable> query;
|
||||
|
||||
/// Populated when the query returns a result.
|
||||
@property (nonatomic, readonly, nullable) FIRDataSnapshot *contents;
|
||||
|
||||
/**
|
||||
* Initializes a FUIQueryObserver
|
||||
*/
|
||||
- (instancetype)initWithQuery:(id<FUIDataObservable>)query NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* Creates a query observer and immediately starts observing the query.
|
||||
*/
|
||||
+ (FUIQueryObserver *)observerForQuery:(id<FUIDataObservable>)query
|
||||
completion:(void (^_Nullable)(FUIQueryObserver *obs,
|
||||
FIRDataSnapshot *_Nullable,
|
||||
NSError *_Nullable))completion;
|
||||
|
||||
/**
|
||||
* Removes all the query's observers. The observer cannot be reused after
|
||||
* this method is called.
|
||||
*/
|
||||
- (void)removeAllObservers;
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@end
|
||||
Generated
+46
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#import "FUIArray.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUISortedArray : FUIArray <FUICollection>
|
||||
|
||||
/**
|
||||
* A copy of the snapshots currently in the array.
|
||||
*/
|
||||
@property (nonatomic, readonly, copy) NSArray<FIRDataSnapshot *> *items;
|
||||
|
||||
- (instancetype)initWithQuery:(id<FUIDataObservable>)query NS_UNAVAILABLE;
|
||||
- (instancetype)initWithQuery:(id<FUIDataObservable>)query
|
||||
delegate:(nullable id<FUICollectionDelegate>)delegate NS_UNAVAILABLE;
|
||||
|
||||
/**
|
||||
* Initializes a sorted collection.
|
||||
* @param query The query the receiver uses to pull updates from Firebase Database.
|
||||
* @param delegate The delegate object that should receive events from the array.
|
||||
* @param sortDescriptor The closure used by the array to sort its contents. This
|
||||
* block must always return consistent results or the array may raise a fatal error.
|
||||
*/
|
||||
- (instancetype)initWithQuery:(id<FUIDataObservable>)query
|
||||
delegate:(nullable id<FUICollectionDelegate>)delegate
|
||||
sortDescriptor:(NSComparisonResult (^)(FIRDataSnapshot *left,
|
||||
FIRDataSnapshot *right))sortDescriptor NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
// 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 <UIKit/UIKit.h>
|
||||
|
||||
#import "FUICollection.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class FIRDatabaseReference;
|
||||
|
||||
/**
|
||||
* FUITableViewDataSource provides a class that conforms to the
|
||||
* UITableViewDataSource protocol which allows UITableViews to implement
|
||||
* FUITableViewDataSource in order to provide a UITableView synchronized
|
||||
* to a Firebase reference or query.
|
||||
*/
|
||||
@interface FUITableViewDataSource : NSObject <UITableViewDataSource>
|
||||
|
||||
/**
|
||||
* The UITableView instance that operations (inserts, removals, moves, etc.) are
|
||||
* performed against. This collection view must be receiving data from
|
||||
* this data source otherwise data inconsistency crashes will occur.
|
||||
*/
|
||||
@property (nonatomic, readwrite, weak, nullable) UITableView *tableView;
|
||||
|
||||
/**
|
||||
* The number of items in the data source.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSUInteger count;
|
||||
|
||||
/**
|
||||
* The snapshots in the data source.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSArray<FIRDataSnapshot *> *items;
|
||||
|
||||
/**
|
||||
* A closure that should be invoked when the query encounters a fatal error.
|
||||
* After this is invoked, the query is no longer valid and the data source should
|
||||
* be recreated.
|
||||
*/
|
||||
@property (nonatomic, copy, readwrite) void (^queryErrorHandler)(NSError *);
|
||||
|
||||
/**
|
||||
* Returns the snapshot at the given index. Throws an exception if the index is out of bounds.
|
||||
*/
|
||||
- (FIRDataSnapshot *)snapshotAtIndex:(NSInteger)index;
|
||||
|
||||
/**
|
||||
* Initialize an instance of FUITableViewDataSource.
|
||||
* @param collection An FUICollection used by the data source to pull data
|
||||
* from Firebase Database.
|
||||
* @param populateCell A closure used by the data source to create/reuse
|
||||
* table view cells and populate their content. This closure is retained
|
||||
* by the data source, so if you capture self in the closure and also claim ownership
|
||||
* of the data source, be sure to avoid retain cycles by capturing a weak reference to self.
|
||||
* @return An instance of FUITableViewDataSource.
|
||||
*/
|
||||
- (instancetype)initWithCollection:(id<FUICollection>)collection
|
||||
populateCell:(UITableViewCell *(^)(UITableView *tableView,
|
||||
NSIndexPath *indexPath,
|
||||
FIRDataSnapshot *object))populateCell NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
|
||||
/**
|
||||
* Initialize an instance of FUITableViewDataSource with contents ordered
|
||||
* by the query.
|
||||
* @param query A Firebase query to bind the data source to.
|
||||
* @param populateCell A closure used by the data source to create/reuse
|
||||
* table view cells and populate their content. This closure is retained
|
||||
* by the data source, so if you capture self in the closure and also claim ownership
|
||||
* of the data source, be sure to avoid retain cycles by capturing a weak reference to self.
|
||||
* @return An instance of FUITableViewDataSource.
|
||||
*/
|
||||
- (instancetype)initWithQuery:(FIRDatabaseQuery *)query
|
||||
populateCell:(UITableViewCell *(^)(UITableView *tableView,
|
||||
NSIndexPath *indexPath,
|
||||
FIRDataSnapshot *object))populateCell;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/**
|
||||
* Attaches the data source to a table view and begins sending updates immediately.
|
||||
* @param view An instance of UITableView that the data source should push
|
||||
* updates to.
|
||||
*/
|
||||
- (void)bindToView:(UITableView *)view;
|
||||
|
||||
/**
|
||||
* Detaches the data source from a view and stops sending any updates.
|
||||
*/
|
||||
- (void)unbind;
|
||||
|
||||
@end
|
||||
|
||||
@interface UITableView (FUITableViewDataSource)
|
||||
|
||||
/**
|
||||
* Creates a data source, attaches it to the table view, and returns it.
|
||||
* The returned data source is not retained by the table view and must be
|
||||
* retained or it will be deallocated while still in use by the table view.
|
||||
* @param query A Firebase database query to bind the table view to.
|
||||
* @param populateCell A closure used by the data source to create the cells
|
||||
* displayed in the table view. The closure is retained by the returned
|
||||
* data source.
|
||||
* @return The created data source. This value must be retained while the table
|
||||
* view is in use.
|
||||
*/
|
||||
- (FUITableViewDataSource *)bindToQuery:(FIRDatabaseQuery *)query
|
||||
populateCell:(UITableViewCell *(^)(UITableView *tableView,
|
||||
NSIndexPath *indexPath,
|
||||
FIRDataSnapshot *object))populateCell __attribute__((warn_unused_result));
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
Generated
+33
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
//! Project version number for FirebaseDatabaseUI.
|
||||
FOUNDATION_EXPORT double FirebaseDatabaseUIVersionNumber;
|
||||
|
||||
//! Project version string for FirebaseDatabaseUI.
|
||||
FOUNDATION_EXPORT const unsigned char FirebaseDatabaseUIVersionString[];
|
||||
|
||||
#import "FUIIndexArray.h"
|
||||
#import "FUIIndexTableViewDataSource.h"
|
||||
#import "FUIIndexCollectionViewDataSource.h"
|
||||
#import "FUIArray.h"
|
||||
#import "FUISortedArray.h"
|
||||
#import "FUICollection.h"
|
||||
#import "FUICollectionViewDataSource.h"
|
||||
#import "FUITableViewDataSource.h"
|
||||
#import "FUIQueryObserver.h"
|
||||
Generated
+202
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
Generated
+156
@@ -0,0 +1,156 @@
|
||||
# FirebaseUI for iOS — UI Bindings for Firebase
|
||||
|
||||
          
|
||||
|
||||
FirebaseUI is an open-source library for iOS that allows you to quickly connect common UI elements to the [Firebase](https://firebase.google.com?utm_source=FirebaseUI-iOS) database for data storage, allowing views to be updated in realtime as they change, and providing simple interfaces for common tasks like displaying lists or collections of items.
|
||||
|
||||
Additionally, FirebaseUI simplifies Firebase authentication by providing easy to use auth methods that integrate with common identity providers like Facebook, Twitter, and Google as well as allowing developers to use a built in headful UI for ease of development.
|
||||
|
||||
FirebaseUI clients are also available for [Android](https://github.com/firebase/FirebaseUI-Android) and [web](https://github.com/firebase/firebaseui-web).
|
||||
|
||||

|
||||
|
||||
## Installing FirebaseUI for iOS
|
||||
|
||||
FirebaseUI supports iOS 10.0+ and Xcode 11+. We recommend using [CocoaPods](https://cocoapods.org/pods/FirebaseUI), add
|
||||
the following to your `Podfile`:
|
||||
|
||||
```ruby
|
||||
pod 'FirebaseUI', '~> 8.0' # Pull in all Firebase UI features
|
||||
```
|
||||
|
||||
If you don't want to use all of FirebaseUI, there are multiple subspecs which can selectively install subsets of the full feature set:
|
||||
|
||||
```ruby
|
||||
# Only pull in Firestore features
|
||||
pod 'FirebaseUI/Firestore', '~> 8.0'
|
||||
|
||||
# Only pull in Database features
|
||||
pod 'FirebaseUI/Database', '~> 8.0'
|
||||
|
||||
# Only pull in Storage features
|
||||
pod 'FirebaseUI/Storage', '~> 8.0'
|
||||
|
||||
# Only pull in Auth features
|
||||
pod 'FirebaseUI/Auth', '~> 8.0'
|
||||
|
||||
# Only pull in Facebook login features
|
||||
pod 'FirebaseUI/Facebook', '~> 8.0'
|
||||
|
||||
# Only pull in Google login features
|
||||
pod 'FirebaseUI/Google', '~> 8.0'
|
||||
|
||||
# Only pull in Phone Auth login features
|
||||
pod 'FirebaseUI/Phone', '~> 8.0'
|
||||
```
|
||||
|
||||
If you're including FirebaseUI in a Swift project, make sure you also have:
|
||||
|
||||
```ruby
|
||||
platform :ios, '10.0'
|
||||
use_frameworks!
|
||||
```
|
||||
|
||||
Otherwise, you can include the FirebaseUI Xcode project from this repo in
|
||||
your project. You also need to
|
||||
[add the Firebase framework](https://firebase.google.com/docs/ios/setup)
|
||||
to your project.
|
||||
|
||||
## Documentation
|
||||
|
||||
The READMEs for components of FirebaseUI can be found in their respective
|
||||
project folders.
|
||||
|
||||
- [Auth](Auth/README.md)
|
||||
- [PhoneAuth](PhoneAuth/README.md)
|
||||
- [Database](Database/README.md)
|
||||
- [Firestore](Firestore/README.md)
|
||||
- [Storage](Storage/README.md)
|
||||
|
||||
## Local Setup
|
||||
|
||||
If you'd like to contribute to FirebaseUI for iOS, you'll need to run the
|
||||
following commands to get your environment set up:
|
||||
|
||||
```bash
|
||||
$ git clone https://github.com/firebase/FirebaseUI-iOS.git
|
||||
$ cd FirebaseUI-iOS
|
||||
$ cd Auth # or PhoneAuth, Database, etc
|
||||
$ pod install
|
||||
```
|
||||
|
||||
Alternatively you can use `pod try FirebaseUI` to install the Objective-C or Swift sample projects.
|
||||
|
||||
## Sample Project Configuration
|
||||
|
||||
You'll have to configure your Xcode project in order to run the samples.
|
||||
|
||||
1. Your Xcode project should contain a `GoogleService-Info.plist`, downloaded from [Firebase console](https://console.firebase.google.com) when you add your app to a Firebase project.<br>
|
||||
Copy the `GoogleService-Info.plist` into the sample project folder (`samples/obj-c/GoogleService-Info.plist` or `samples/swift/GoogleService-Info.plist`).
|
||||
|
||||
1. Update URL Types.<br>
|
||||
Go to `Project Settings -> Info tab -> Url Types` and update values for:
|
||||
+ `REVERSED_CLIENT_ID` (get value from `GoogleService-Info.plist`)
|
||||
+ `fb{your-app-id}` (put Facebook App Id)
|
||||
|
||||
1. Update `Info.plist` with Facebook configuration values
|
||||
+ `FacebookAppID -> {your-app-id}` (put Facebook App Id)
|
||||
|
||||
1. Enable Keychain Sharing.<br>
|
||||
Facebook SDK requires keychain sharing.<br>
|
||||
This can be done here: `Project Settings -> Capabilities -> KeyChain Sharing -> ON`
|
||||
|
||||
1. Don't forget to configure your Firebase App Database using [Firebase console](https://console.firebase.google.com).<br>
|
||||
Database should contain appropriate read/write permissions and folders (`objc_demo-chat` and `swift_demo-chat` respectively)
|
||||
|
||||
1. In Order to use `Phone Auth` provider you should [Configure Push Notifications](#configure-apple-push-notifications)
|
||||
|
||||
#### Configure Apple Push Notifications
|
||||
|
||||
##### Enable silent push notifications in Xcode
|
||||
|
||||
* `Push Notification` - Under `Capabilities` tab in your app target choose `Push Notifications` and put the switch to the `On` position.
|
||||
* `Background Mode` - Under `Capabilities` tab in your app target choose `Background Modes` put the switch to the `On` position. In the list of available modes select `Background fetch` and `Remote notifications` (If available).
|
||||
|
||||
##### Upload APNS Certificate to Firebase
|
||||
|
||||
1. Create your `Provisioning APNS SSL Certificates` by following the steps on the following link.
|
||||
https://firebase.google.com/docs/cloud-messaging/ios/certs
|
||||
|
||||
1. Upload your `APNS Certificate` to Firebase:
|
||||
+ Inside your project in the Firebase console, select the gear icon, select `Project Settings`, and then select the `Cloud Messaging` tab.
|
||||
+ Select the `Upload Certificate` button for your development certificate, your production certificate, or both. At least one is required.
|
||||
+ For each certificate, select the `.p12 file`, and provide the password, if any. Make sure the `bundle ID` for this certificate matches the `bundle ID` of your app. Select `Save`.
|
||||
|
||||
## Contributing to FirebaseUI
|
||||
|
||||
### Contributor License Agreements
|
||||
|
||||
We'd love to accept your sample apps and patches! Before we can take them, we
|
||||
have to jump a couple of legal hurdles.
|
||||
|
||||
Please fill out either the individual or corporate Contributor License Agreement
|
||||
(CLA).
|
||||
|
||||
* If you are an individual writing original source code and you're sure you
|
||||
own the intellectual property, then you'll need to sign an [individual CLA]
|
||||
(https://developers.google.com/open-source/cla/individual).
|
||||
* If you work for a company that wants to allow you to contribute your work,
|
||||
then you'll need to sign a [corporate CLA]
|
||||
(https://developers.google.com/open-source/cla/corporate).
|
||||
|
||||
Follow either of the two links above to access the appropriate CLA and
|
||||
instructions for how to sign and return it. Once we receive it, we'll be able to
|
||||
accept your pull requests.
|
||||
|
||||
### Contribution Process
|
||||
|
||||
1. Submit an issue describing your proposed change to the repo in question.
|
||||
1. The repo owner will respond to your issue promptly.
|
||||
1. If your proposed change is accepted, and you haven't already done so, sign a
|
||||
Contributor License Agreement (see details above).
|
||||
1. Fork the desired repo, develop and test your code changes.
|
||||
1. Ensure that your code adheres to the existing style of the library to which
|
||||
you are contributing.
|
||||
1. Ensure that your code has an appropriate set of unit tests which all pass.
|
||||
1. Submit a pull request
|
||||
Reference in New Issue
Block a user