From 8eb363d9982e8bc15b459fdd5e23f5d1248a1a54 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Wed, 19 Oct 2016 16:57:17 -0700 Subject: [PATCH 1/4] remove cell registration and creation from collection view data source --- FirebaseDatabaseUI/FirebaseArray.h | 2 +- .../FirebaseCollectionViewDataSource.h | 348 +----------------- .../FirebaseCollectionViewDataSource.m | 245 +----------- 3 files changed, 19 insertions(+), 576 deletions(-) diff --git a/FirebaseDatabaseUI/FirebaseArray.h b/FirebaseDatabaseUI/FirebaseArray.h index 2cb32ea37a3..59c40259dce 100644 --- a/FirebaseDatabaseUI/FirebaseArray.h +++ b/FirebaseDatabaseUI/FirebaseArray.h @@ -47,7 +47,7 @@ NS_ASSUME_NONNULL_BEGIN /** * The delegate object that array changes are surfaced to, which conforms to the - * [FirebaseArrayDelegate Protocol](FirebaseArrayDelegate). + * @c FirebaseArrayDelegate protocol. */ @property(weak, nonatomic, nullable) id delegate; diff --git a/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.h b/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.h index 228f4ff16d4..76eb65c47d0 100644 --- a/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.h +++ b/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.h @@ -46,203 +46,19 @@ NS_ASSUME_NONNULL_BEGIN */ @interface FirebaseCollectionViewDataSource : FirebaseDataSource -/** - * The model class to coerce FIRDataSnapshots to (if desired). For instance, if - * the modelClass is set - * to [Message class] in Obj-C or Message.self in Swift, then objects of type - * Message will be - * returned instead of type FIRDataSnapshot. - * Defaults to FIRDataSnapshot. - */ -@property(strong, nonatomic, null_resettable) Class modelClass; - -/** - * The cell class to coerce UICollectionViewCells to (if desired). For instance, - * if the cellClass is - * set to [CustomCollectionViewCell class] in Obj-C or CustomCollectionViewCell - * in Swift, then - * objects of type CustomCollectionViewCell will be returned instead of type - * UICollectionViewCell. - * Defaults to UICollectionViewCell. - */ -@property(strong, nonatomic, null_resettable) Class cellClass; - -/** - * The reuse identifier for cells in the UICollectionView. - */ -@property(strong, nonatomic) NSString *reuseIdentifier; - /** * The UICollectionView instance that operations (inserts, removals, moves, - * etc.) are performed - * against. + * etc.) are performed against. The data source does not claim ownership of + * the collection view it populates. */ -@property(strong, nonatomic) UICollectionView *collectionView; - -/** - * Property to keep track of prototype cell use, to not register a class for the - * UICollectionView or - * do similar book keeping. - */ -@property BOOL hasPrototypeCell; +@property (nonatomic, readonly, weak) UICollectionView *collectionView; /** * The callback to populate a subclass of UICollectionViewCell with an object - * provided by the - * datasource. - */ -@property(strong, nonatomic, readonly) void (^populateCell) - (__kindof UICollectionViewCell *cell, __kindof NSObject *object); - -/** - * Initialize an instance of FirebaseCollectionViewDataSource that populates - * UICollectionViewCells - * with FIRDataSnapshots. - * @param ref A Firebase reference to bind the datasource to - * @param identifier A string to use as a CellReuseIdentifier - * @param collectionView An instance of a UICollectionView to bind to - * @return An instance of FirebaseCollectionViewDataSource that populates - * UICollectionViewCells with - * FIRDataSnapshots - */ -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; - -/** - * Initialize an instance of FirebaseCollectionViewDataSource that populates - * UICollectionViewCells - * with FIRDataSnapshots. Note that this method is used when using prototype - * cells, where the cells - * don't need to be registered in the class. - * @param ref A Firebase reference to bind the datasource to - * @param identifier A string to use as a CellReuseIdentifier - * @param collectionView An instance of a UICollectionView to bind to - * @return An instance of FirebaseCollectionViewDataSource that populates - * UICollectionViewCells with - * FIRDataSnapshots - */ -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - prototypeReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; - -/** - * Initialize an instance of FirebaseCollectionViewDataSource that populates a - * custom subclass of - * UICollectionViewCell with FIRDataSnapshots. - * @param ref A Firebase reference to bind the datasource to - * @param cell A subclass of UICollectionViewCell used to populate the - * UICollectionView, defaults to - * UICollectionViewCell if nil - * @param identifier A string to use as a CellReuseIdentifier - * @param collectionView An instance of a UICollectionView to bind to - * @return An instance of FirebaseCollectionViewDataSource that populates a - * custom subclass of - * UICollectionViewCell with FIRDataSnapshots - */ -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - cellClass:(nullable Class)cell - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; - -/** - * Initialize an instance of FirebaseCollectionViewDataSource that populates a - * custom xib with - * FIRDataSnapshots. - * @param ref A Firebase reference to bind the datasource to - * @param nibName The name of a xib file to create the layout for a - * UICollectionViewCell - * @param identifier A string to use as a CellReuseIdentifier - * @param collectionView An instance of a UICollectionView to bind to - * @return An instance of FirebaseCollectionViewDataSource that populates a - * custom xib with - * FIRDataSnapshots - */ -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; - -/** - * Initialize an instance of FirebaseCollectionViewDataSource that populates - * UICollectionViewCells - * with a custom model class. - * @param ref A Firebase reference to bind the datasource to - * @param model A custom class that FIRDataSnapshots are coerced to, defaults to - * FIRDataSnapshot if nil - * @param identifier A string to use as a CellReuseIdentifier - * @param collectionView An instance of a UICollectionView to bind to - * @return An instance of FirebaseCollectionViewDataSource that populates - * UICollectionViewCells with - * a custom model class - */ -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(nullable Class)model - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; - -/** - * Initialize an instance of FirebaseCollectionViewDataSource that populates - * UICollectionViewCells - * with a custom model class. Note that this method is used when using prototype - * cells, where the - * cells don't need to be registered in the class. - * @param ref A Firebase reference to bind the datasource to - * @param model A custom class that FIRDataSnapshots are coerced to, defaults to - * FIRDataSnapshot if nil - * @param identifier A string to use as a CellReuseIdentifier - * @param collectionView An instance of a UICollectionView to bind to - * @return An instance of FirebaseCollectionViewDataSource that populates - * UICollectionViewCells with - * a custom model class - */ -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(nullable Class)model - prototypeReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; - -/** - * Initialize an instance of FirebaseCollectionViewDataSource that populates a - * custom subclass of - * UICollectionViewCell with a custom model class. - * @param ref A Firebase reference to bind the datasource to - * @param model A custom class that FIRDataSnapshots are coerced to, defaults to - * FIRDataSnapshot if nil - * @param cell A subclass of UICollectionViewCell used to populate the - * UICollectionView, defaults to - * UICollectionViewCell if nil - * @param identifier A string to use as a CellReuseIdentifier - * @param collectionView An instance of a UICollectionView to bind to - * @return An instance of FirebaseCollectionViewDataSource that populates a - * custom subclass of - * UICollectionViewCell with a custom model class - */ -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(nullable Class)model - cellClass:(nullable Class)cell - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; - -/** - * Initialize an instance of FirebaseCollectionViewDataSource that populates a - * custom xib with a - * custom model class. - * @param ref A Firebase reference to bind the datasource to - * @param model A custom class that FIRDataSnapshots are coerced to, defaults to - * FIRDataSnapshot if nil - * @param nibName The name of a xib file to create the layout for a - * UICollectionViewCell - * @param identifier A string to use as a CellReuseIdentifier - * @param collectionView An instance of a UICollectionView to bind to - * @return An instance of FirebaseCollectionViewDataSource that populates a - * custom xib with a custom - * model class + * provided by the datasource. */ -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(nullable Class)model - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; +@property(strong, nonatomic, readonly) UICollectionViewCell *(^populateCellAtIndexPath) + (NSIndexPath *indexPath, UICollectionView *collectionView, FIRDataSnapshot *object); /** * Initialize an instance of FirebaseCollectionViewDataSource that populates @@ -256,154 +72,10 @@ NS_ASSUME_NONNULL_BEGIN * FIRDataSnapshots */ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; - -/** - * Initialize an instance of FirebaseCollectionViewDataSource that populates - * UICollectionViewCells - * with FIRDataSnapshots. Note that this method is used when using prototype - * cells, where the cells - * don't need to be registered in the class. - * @param query A Firebase query to bind the datasource to - * @param identifier A string to use as a CellReuseIdentifier - * @param collectionView An instance of a UICollectionView to bind to - * @return An instance of FirebaseCollectionViewDataSource that populates - * UICollectionViewCells with - * FIRDataSnapshots - */ -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - prototypeReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; - -/** - * Initialize an instance of FirebaseCollectionViewDataSource that populates a - * custom subclass of - * UICollectionViewCell with FIRDataSnapshots. - * @param query A Firebase query to bind the datasource to - * @param cell A subclass of UICollectionViewCell used to populate the - * UICollectionView, defaults to - * UICollectionViewCell if nil - * @param identifier A string to use as a CellReuseIdentifier - * @param collectionView An instance of a UICollectionView to bind to - * @return An instance of FirebaseCollectionViewDataSource that populates a - * custom subclass of - * UICollectionViewCell with FIRDataSnapshots - */ -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - cellClass:(nullable Class)cell - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; - -/** - * Initialize an instance of FirebaseCollectionViewDataSource that populates a - * custom xib with - * FIRDataSnapshots. - * @param query A Firebase query to bind the datasource to - * @param nibName The name of a xib file to create the layout for a - * UICollectionViewCell - * @param identifier A string to use as a CellReuseIdentifier - * @param collectionView An instance of a UICollectionView to bind to - * @return An instance of FirebaseCollectionViewDataSource that populates a - * custom xib with - * FIRDataSnapshots - */ -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; - -/** - * Initialize an instance of FirebaseCollectionViewDataSource that populates - * UICollectionViewCells - * with a custom model class. - * @param query A Firebase query to bind the datasource to - * @param model A custom class that FIRDataSnapshots are coerced to, defaults to - * FIRDataSnapshot if nil - * @param identifier A string to use as a CellReuseIdentifier - * @param collectionView An instance of a UICollectionView to bind to - * @return An instance of FirebaseCollectionViewDataSource that populates - * UICollectionViewCells with - * a custom model class - */ -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - modelClass:(nullable Class)model - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; - -/** - * Initialize an instance of FirebaseCollectionViewDataSource that populates - * UICollectionViewCells - * with a custom model class. Note that this method is used when using prototype - * cells, where the - * cells don't need to be registered in the class. - * @param query A Firebase query to bind the datasource to - * @param model A custom class that FIRDataSnapshots are coerced to, defaults to - * FIRDataSnapshot if nil - * @param identifier A string to use as a CellReuseIdentifier - * @param collectionView An instance of a UICollectionView to bind to - * @return An instance of FirebaseCollectionViewDataSource that populates - * UICollectionViewCells with - * a custom model class - */ -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - modelClass:(nullable Class)model - prototypeReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; - -/** - * Initialize an instance of FirebaseCollectionViewDataSource that populates a - * custom subclass of - * UICollectionViewCell with a custom model class. - * @param query A Firebase query to bind the datasource to - * @param model A custom class that FIRDataSnapshots are coerced to, defaults to - * FIRDataSnapshot if nil - * @param cell A subclass of UICollectionViewCell used to populate the - * UICollectionView, defaults to - * UICollectionViewCell if nil - * @param identifier A string to use as a CellReuseIdentifier - * @param collectionView An instance of a UICollectionView to bind to - * @return An instance of FirebaseCollectionViewDataSource that populates a - * custom subclass of - * UICollectionViewCell with a custom model class - */ -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - modelClass:(nullable Class)model - cellClass:(nullable Class)cell - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; - -/** - * Initialize an instance of FirebaseCollectionViewDataSource that populates a - * custom xib with a - * custom model class. - * @param query A Firebase query to bind the datasource to - * @param model A custom class that FIRDataSnapshots are coerced to, defaults to - * FIRDataSnapshot if nil - * @param nibName The name of a xib file to create the layout for a - * UICollectionViewCell - * @param identifier A string to use as a CellReuseIdentifier - * @param collectionView An instance of a UICollectionView to bind to - * @return An instance of FirebaseCollectionViewDataSource that populates a - * custom xib with a custom - * model class - */ -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - modelClass:(nullable Class)model - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; - -/** - * This method populates the fields of a UICollectionViewCell or subclass given - * an FIRDataSnapshot (or - * custom model object). - * @param callback A block which returns an initialized UICollectionViewCell (or - * subclass) and the - * corresponding object to populate the cell with. - */ -- (void)populateCellWithBlock:(void (^)(__kindof UICollectionViewCell *cell, - __kindof NSObject *object))callback; + view:(UICollectionView *)collectionView + populateCell:(UICollectionViewCell * (^)(NSIndexPath *indexPath, + UICollectionView *collectionView, + FIRDataSnapshot *object))populateCell; @end diff --git a/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.m b/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.m index 8c10cebc6b9..94bbab38fee 100644 --- a/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.m +++ b/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.m @@ -22,216 +22,20 @@ @import FirebaseDatabase; -@interface FirebaseCollectionViewDataSource () -@property(strong, nonatomic, readwrite) void (^populateCell) -(__kindof UICollectionViewCell *cell, __kindof NSObject *object); -@end - @implementation FirebaseCollectionViewDataSource #pragma mark - FirebaseDataSource initializer methods -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView { - return [self initWithQuery:ref - modelClass:nil - cellClass:nil - cellReuseIdentifier:identifier - view:collectionView]; -} - -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - prototypeReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView { - return [self initWithQuery:ref - modelClass:nil - prototypeReuseIdentifier:identifier - view:collectionView]; -} - -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - cellClass:(Class)cell - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView { - return [self initWithQuery:ref - modelClass:nil - cellClass:cell - cellReuseIdentifier:identifier - view:collectionView]; -} - -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView { - return [self initWithQuery:ref - modelClass:nil - nibNamed:nibName - cellReuseIdentifier:identifier - view:collectionView]; -} - -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(Class)model - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView { - return [self initWithQuery:ref - modelClass:model - cellClass:nil - cellReuseIdentifier:identifier - view:collectionView]; -} - -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(Class)model - prototypeReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView { - return [self initWithQuery:ref - modelClass:model - prototypeReuseIdentifier:identifier - view:collectionView]; -} - -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(Class)model - cellClass:(Class)cell - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView { - return [self initWithQuery:ref - modelClass:model - cellClass:cell - cellReuseIdentifier:identifier - view:collectionView]; -} - -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(Class)model - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView { - return [self initWithQuery:ref - modelClass:model - nibNamed:nibName - cellReuseIdentifier:identifier - view:collectionView]; -} - -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView { - return [self initWithQuery:query - modelClass:nil - cellClass:nil - cellReuseIdentifier:identifier - view:collectionView]; -} - -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - prototypeReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView { - self.hasPrototypeCell = YES; - return [self initWithQuery:query - modelClass:nil - cellClass:nil - cellReuseIdentifier:identifier - view:collectionView]; -} - - (instancetype)initWithQuery:(FIRDatabaseQuery *)query - cellClass:(Class)cell - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView { - return [self initWithQuery:query - modelClass:nil - cellClass:cell - cellReuseIdentifier:identifier - view:collectionView]; -} - -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView { - return [self initWithQuery:query - modelClass:nil - nibNamed:nibName - cellReuseIdentifier:identifier - view:collectionView]; -} - -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - modelClass:(Class)model - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView { - return [self initWithQuery:query - modelClass:model - cellClass:nil - cellReuseIdentifier:identifier - view:collectionView]; -} - -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - modelClass:(Class)model - prototypeReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView { - self.hasPrototypeCell = YES; - return [self initWithQuery:query - modelClass:model - cellClass:nil - cellReuseIdentifier:identifier - view:collectionView]; -} - -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - modelClass:(Class)model - cellClass:(Class)cell - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView { - FirebaseArray *array = [[FirebaseArray alloc] initWithQuery:query]; - self = [super initWithArray:array]; - if (self) { - if (!model) { - model = [FIRDataSnapshot class]; - } - - if (!cell) { - cell = [UICollectionViewCell class]; - } - - self.collectionView = collectionView; - self.modelClass = model; - self.cellClass = cell; - self.reuseIdentifier = identifier; - self.populateCell = ^(id cell, id object) {}; - - if (!self.hasPrototypeCell) { - [self.collectionView registerClass:self.cellClass - forCellWithReuseIdentifier:self.reuseIdentifier]; - } - } - return self; -} - -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - modelClass:(Class)model - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView { + view:(UICollectionView *)collectionView + populateCell:(UICollectionViewCell *(^)(NSIndexPath *, + UICollectionView *, + FIRDataSnapshot *))populateCell { FirebaseArray *array = [[FirebaseArray alloc] initWithQuery:query]; self = [super initWithArray:array]; if (self) { - if (!model) { - model = [FIRDataSnapshot class]; - } - - self.collectionView = collectionView; - self.modelClass = model; - self.reuseIdentifier = identifier; - self.populateCell = ^(id cell, id object) {}; - - UINib *nib = [UINib nibWithNibName:nibName bundle:nil]; - [self.collectionView registerNib:nib forCellWithReuseIdentifier:self.reuseIdentifier]; + _collectionView = collectionView; + _populateCellAtIndexPath = populateCell; } return self; } @@ -263,19 +67,9 @@ - (void)array:(FirebaseArray *)array didMoveObject:(id)object - (nonnull UICollectionViewCell *)collectionView:(nonnull UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { - id cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:self.reuseIdentifier - forIndexPath:indexPath]; - FIRDataSnapshot *snap = [self.items objectAtIndex:indexPath.row]; - if (![self.modelClass isSubclassOfClass:[FIRDataSnapshot class]]) { - id model = [[self.modelClass alloc] init]; - // TODO: replace setValuesForKeysWithDictionary with client API - // valueAsObject method - [model setValuesForKeysWithDictionary:snap.value]; - self.populateCell(cell, model); - } else { - self.populateCell(cell, snap); - } + + UICollectionViewCell *cell = self.populateCellAtIndexPath(indexPath, collectionView, snap); return cell; } @@ -289,27 +83,4 @@ - (NSInteger)collectionView:(nonnull UICollectionView *)collectionView return self.count; } -- (void)populateCellWithBlock:(void (^)(__kindof UICollectionViewCell *cell, - __kindof NSObject *object))callback { - self.populateCell = callback; -} - -#pragma mark - Accessors - -- (void)setModelClass:(Class)modelClass { - if (modelClass == nil) { - _modelClass = [FIRDataSnapshot class]; - } else { - _modelClass = modelClass; - } -} - -- (void)setCellClass:(Class)cellClass { - if (cellClass == nil) { - _cellClass = [UICollectionViewCell class]; - } else { - _cellClass = cellClass; - } -} - @end From 3c286b9ad4793d942627ebed7ab685455e4332b6 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Wed, 19 Oct 2016 17:10:11 -0700 Subject: [PATCH 2/4] change tests for new api --- FirebaseDatabaseUI/FirebaseCollectionViewDataSource.h | 1 - .../FirebaseCollectionViewDataSourceTest.m | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.h b/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.h index 76eb65c47d0..cef0f5d70a4 100644 --- a/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.h +++ b/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.h @@ -65,7 +65,6 @@ NS_ASSUME_NONNULL_BEGIN * UICollectionViewCells * with FIRDataSnapshots. * @param query A Firebase query to bind the datasource to - * @param identifier A string to use as a CellReuseIdentifier * @param collectionView An instance of a UICollectionView to bind to * @return An instance of FirebaseCollectionViewDataSource that populates * UICollectionViewCells with diff --git a/FirebaseDatabaseUITests/FirebaseCollectionViewDataSourceTest.m b/FirebaseDatabaseUITests/FirebaseCollectionViewDataSourceTest.m index 9645b1f1b62..61a578814b9 100644 --- a/FirebaseDatabaseUITests/FirebaseCollectionViewDataSourceTest.m +++ b/FirebaseDatabaseUITests/FirebaseCollectionViewDataSourceTest.m @@ -44,12 +44,12 @@ - (void)setUp { self.observable = [[FUITestObservable alloc] init]; // Horrible abuse of type system, knowing that the initializer passes the observable straight to // FirebaseArray anyway. - self.dataSource = [[FirebaseCollectionViewDataSource alloc] initWithRef:(FIRDatabaseReference *)self.observable - cellReuseIdentifier:kTestReuseIdentifier - view:self.collectionView]; - [self.dataSource populateCellWithBlock:^(__kindof UICollectionViewCell *_Nonnull cell, - FUIFakeSnapshot * _Nonnull object) { + self.dataSource = [[FirebaseCollectionViewDataSource alloc] initWithQuery:(FIRDatabaseReference *)self.observable + view:self.collectionView + populateCell:^UICollectionViewCell *(NSIndexPath *indexPath, UICollectionView *collectionView, FIRDataSnapshot *object) { + UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kTestReuseIdentifier forIndexPath:indexPath]; cell.accessibilityValue = object.key; + return cell; }]; self.collectionView.dataSource = self.dataSource; From 752624884a9b7951469d52bc231e56793681b15a Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Thu, 20 Oct 2016 10:58:17 -0700 Subject: [PATCH 3/4] refactor table view data source --- .../FirebaseCollectionViewDataSource.h | 25 +- .../FirebaseCollectionViewDataSource.m | 6 +- .../FirebaseTableViewDataSource.h | 371 ++---------------- .../FirebaseTableViewDataSource.m | 241 +----------- .../FirebaseCollectionViewDataSourceTest.m | 2 +- .../FirebaseTableViewDataSourceTest.m | 12 +- 6 files changed, 65 insertions(+), 592 deletions(-) diff --git a/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.h b/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.h index cef0f5d70a4..d3650c5eaf0 100644 --- a/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.h +++ b/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.h @@ -58,23 +58,28 @@ NS_ASSUME_NONNULL_BEGIN * provided by the datasource. */ @property(strong, nonatomic, readonly) UICollectionViewCell *(^populateCellAtIndexPath) - (NSIndexPath *indexPath, UICollectionView *collectionView, FIRDataSnapshot *object); + (UICollectionView *collectionView, NSIndexPath *indexPath, FIRDataSnapshot *object); /** * Initialize an instance of FirebaseCollectionViewDataSource that populates - * UICollectionViewCells - * with FIRDataSnapshots. - * @param query A Firebase query to bind the datasource to - * @param collectionView An instance of a UICollectionView to bind to + * UICollectionViewCells with FIRDataSnapshots. + * @param query A Firebase query to bind the data source to. + * @param collectionView An instance of a UICollectionView to bind to. This view + * is not retained by its data source. + * @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 FirebaseCollectionViewDataSource that populates - * UICollectionViewCells with - * FIRDataSnapshots + * UICollectionViewCells with FIRDataSnapshots. */ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query view:(UICollectionView *)collectionView - populateCell:(UICollectionViewCell * (^)(NSIndexPath *indexPath, - UICollectionView *collectionView, - FIRDataSnapshot *object))populateCell; + populateCell:(UICollectionViewCell *(^)(UICollectionView *collectionView, + NSIndexPath *indexPath, + FIRDataSnapshot *object))populateCell NS_DESIGNATED_INITIALIZER; + +- (instancetype)initWithArray:(FirebaseArray *)array NS_UNAVAILABLE; @end diff --git a/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.m b/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.m index 94bbab38fee..a8954832c00 100644 --- a/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.m +++ b/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.m @@ -28,8 +28,8 @@ @implementation FirebaseCollectionViewDataSource - (instancetype)initWithQuery:(FIRDatabaseQuery *)query view:(UICollectionView *)collectionView - populateCell:(UICollectionViewCell *(^)(NSIndexPath *, - UICollectionView *, + populateCell:(UICollectionViewCell *(^)(UICollectionView *, + NSIndexPath *, FIRDataSnapshot *))populateCell { FirebaseArray *array = [[FirebaseArray alloc] initWithQuery:query]; self = [super initWithArray:array]; @@ -69,7 +69,7 @@ - (nonnull UICollectionViewCell *)collectionView:(nonnull UICollectionView *)col cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { FIRDataSnapshot *snap = [self.items objectAtIndex:indexPath.row]; - UICollectionViewCell *cell = self.populateCellAtIndexPath(indexPath, collectionView, snap); + UICollectionViewCell *cell = self.populateCellAtIndexPath(collectionView, indexPath, snap); return cell; } diff --git a/FirebaseDatabaseUI/FirebaseTableViewDataSource.h b/FirebaseDatabaseUI/FirebaseTableViewDataSource.h index 6b840c71c81..114d3c747eb 100644 --- a/FirebaseDatabaseUI/FirebaseTableViewDataSource.h +++ b/FirebaseDatabaseUI/FirebaseTableViewDataSource.h @@ -18,7 +18,7 @@ // clang-format on -#import +@import UIKit; #import "FirebaseDataSource.h" @@ -28,366 +28,49 @@ NS_ASSUME_NONNULL_BEGIN /** * FirebaseTableViewDataSource provides an class that conforms to the - * UITableViewDataSource protocol - * which allows UITableViews to implement FirebaseTableViewDataSource in order - * to provide a - * UITableView synchronized to a Firebase reference or query. In addition to - * handling all Firebase - * child events (added, changed, removed, moved), FirebaseTableViewDataSource - * handles - * UITableViewCell creation, either with the default UITableViewCell, prototype - * cells, custom - * UITableViewCell subclasses, or custom XIBs, and provides a simple - * [FirebaseTableViewDataSource - * populateCellWithBlock:] method which allows developers to populate the cells - * created for them + * UITableViewDataSource protocol which allows UITableViews to implement + * FirebaseTableViewDataSource in order to provide a UITableView synchronized + * to a Firebase reference or query. In addition to handling all Firebase + * child events (added, changed, removed, moved), FirebaseTableViewDataSource + * handles UITableViewCell creation, either with the default UITableViewCell, + * prototype cells, custom UITableViewCell subclasses, or custom XIBs, and + * provides a simple [FirebaseTableViewDataSource populateCellWithBlock:] + * method which allows developers to populate the cells created for them * with desired data from Firebase. */ @interface FirebaseTableViewDataSource : FirebaseDataSource -/** - * The model class to coerce FIRDataSnapshots to (if desired). For instance, if - * the modelClass is set - * to [Message class] in Obj-C or Message.self in Swift, then objects of type - * Message will be - * returned instead of type FIRDataSnapshot. - * Defaults to FIRDataSnapshot. - */ -@property(strong, nonatomic, null_resettable) Class modelClass; - -/** - * The reuse identifier for cells in the UITableView. - */ -@property(strong, nonatomic) NSString *reuseIdentifier; - /** * The UITableView instance that operations (inserts, removals, moves, etc.) are * performed against. */ -@property(strong, nonatomic) UITableView *tableView; - -/** - * Property to keep track of prototype cell use, to not register a class for the - * UICollectionView or - * do similar book keeping. - */ -@property BOOL hasPrototypeCell; - -/** - * The callback to populate a subclass of UITableViewCell with an object - * provided by the datasource. - */ -@property(strong, nonatomic, readonly) void (^populateCell) - (__kindof UITableViewCell *cell,__kindof NSObject *object); - -/** - * Initialize an instance of FirebaseTableViewDataSource that populates - * UITableViewCells with - * FIRDataSnapshots. - * @param ref A Firebase reference to bind the datasource to - * @param identifier A string to use as a CellReuseIdentifier - * @param tableView An instance of a UITableView to bind to - * @return An instance of FirebaseTableViewDataSource that populates - * UITableViewCells with - * FIRDataSnapshots - */ -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView; - -/** - * Initialize an instance of FirebaseTableViewDataSource that populates - * UITableViewCells with - * FIRDataSnapshots. Note that this method is used when using prototype cells, - * where the cells don't - * need to be registered in the class. - * @param ref A Firebase reference to bind the datasource to - * @param identifier A string to use as a CellReuseIdentifier - * @param tableView An instance of a UITableView to bind to - * @return An instance of FirebaseTableViewDataSource that populates - * UITableViewCells with - * FIRDataSnapshots - */ -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - prototypeReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView; - -/** - * Initialize an instance of FirebaseTableViewDataSource that populates a custom - * subclass of - * UITableViewCell with FIRDataSnapshots. - * @param ref A Firebase reference to bind the datasource to - * @param cell A subclass of UITableViewCell used to populate the UITableView, - * defaults to - * UITableViewCell if nil - * @param identifier A string to use as a CellReuseIdentifier - * @param tableView An instance of a UITableView to bind to - * @return An instance of FirebaseTableViewDataSource that populates a custom - * subclass of - * UITableViewCell with FIRDataSnapshots - */ -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - cellClass:(nullable Class)cell - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView; - -/** - * Initialize an instance of FirebaseTableViewDataSource that populates a custom - * xib with - * FIRDataSnapshots. - * @param ref A Firebase reference to bind the datasource to - * @param nibName The name of a xib file to create the layout for a - * UITableViewCell - * @param identifier A string to use as a CellReuseIdentifier - * @param tableView An instance of a UITableView to bind to - * @return An instance of FirebaseTableViewDataSource that populates a custom - * xib with - * FIRDataSnapshots - */ -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView; - -/** - * Initialize an instance of FirebaseTableViewDataSource that populates - * UITableViewCells with a - * custom model class. - * @param ref A Firebase reference to bind the datasource to - * @param model A custom class that FIRDataSnapshots are coerced to, defaults to - * FIRDataSnapshot if nil - * @param identifier A string to use as a CellReuseIdentifier - * @param tableView An instance of a UITableView to bind to - * @return An instance of FirebaseTableViewDataSource that populates - * UITableViewCells with a custom - * model class - */ -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(nullable Class)model - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView; - -/** - * Initialize an instance of FirebaseTableViewDataSource that populates - * UITableViewCells with a - * custom model class. Note that this method is used when using prototype cells, - * where the cells - * don't need to be registered in the class. - * @param ref A Firebase reference to bind the datasource to - * @param model A custom class that FIRDataSnapshots are coerced to, defaults to - * FIRDataSnapshot if nil - * @param identifier A string to use as a CellReuseIdentifier - * @param tableView An instance of a UITableView to bind to - * @return An instance of FirebaseTableViewDataSource that populates - * UITableViewCells with a custom - * model class - */ -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(nullable Class)model - prototypeReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView; - -/** - * Initialize an instance of FirebaseTableViewDataSource that populates a custom - * subclass of - * UITableViewCell with a custom model class. - * @param ref A Firebase reference to bind the datasource to - * @param model A custom class that FIRDataSnapshots are coerced to, defaults to - * FIRDataSnapshot if nil - * @param cell A subclass of UITableViewCell used to populate the UITableView, - * defaults to - * UITableViewCell if nil - * @param identifier A string to use as a CellReuseIdentifier - * @param tableView An instance of a UITableView to bind to - * @return An instance of FirebaseTableViewDataSource that populates a custom - * subclass of - * UITableViewCell with a custom model class - */ -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(nullable Class)model - cellClass:(nullable Class)cell - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView; - -/** - * Initialize an instance of FirebaseTableViewDataSource that populates a custom - * xib with a custom - * model class. - * @param ref A Firebase reference to bind the datasource to - * @param model A custom class that FIRDataSnapshots are coerced to, defaults to - * FIRDataSnapshot if nil - * @param nibName The name of a xib file to create the layout for a - * UITableViewCell - * @param identifier A string to use as a CellReuseIdentifier - * @param tableView An instance of a UITableView to bind to - * @return An instance of FirebaseTableViewDataSource that populates a custom - * xib with a custom - * model class - */ -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(nullable Class)model - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView; - -/** - * Initialize an instance of FirebaseTableViewDataSource that populates - * UITableViewCells with - * FIRDataSnapshots. - * @param query A Firebase query to bind the datasource to - * @param identifier A string to use as a CellReuseIdentifier - * @param tableView An instance of a UITableView to bind to - * @return An instance of FirebaseTableViewDataSource that populates - * UITableViewCells with - * FIRDataSnapshots - */ -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView; +@property (nonatomic, readonly, weak) UITableView *tableView; /** - * Initialize an instance of FirebaseTableViewDataSource that populates - * UITableViewCells with - * FIRDataSnapshots. Note that this method is used when using prototype cells, - * where the cells don't - * need to be registered in the class. - * @param query A Firebase query to bind the datasource to - * @param identifier A string to use as a CellReuseIdentifier - * @param tableView An instance of a UITableView to bind to - * @return An instance of FirebaseTableViewDataSource that populates - * UITableViewCells with - * FIRDataSnapshots + * The callback used by the data source to populate the table view. */ -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - prototypeReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView; +@property(strong, nonatomic, readonly) UITableViewCell *(^populateCell) + (UITableView *tableView, NSIndexPath *indexPath, FIRDataSnapshot *snap); -/** - * Initialize an instance of FirebaseTableViewDataSource that populates a custom - * subclass of - * UITableViewCell with FIRDataSnapshots. - * @param query A Firebase query to bind the datasource to - * @param cell A subclass of UITableViewCell used to populate the UITableView, - * defaults to - * UITableViewCell if nil - * @param identifier A string to use as a CellReuseIdentifier - * @param tableView An instance of a UITableView to bind to - * @return An instance of FirebaseTableViewDataSource that populates a custom - * subclass of - * UITableViewCell with FIRDataSnapshots - */ -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - cellClass:(nullable Class)cell - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView; /** - * Initialize an instance of FirebaseTableViewDataSource that populates a custom - * xib with - * FIRDataSnapshots. - * @param query A Firebase query to bind the datasource to - * @param nibName The name of a xib file to create the layout for a - * UITableViewCell - * @param identifier A string to use as a CellReuseIdentifier - * @param tableView An instance of a UITableView to bind to - * @return An instance of FirebaseTableViewDataSource that populates a custom - * xib with - * FIRDataSnapshots + * Initialize an instance of FirebaseTableViewDataSource. + * @param query A Firebase query to bind the data source to. + * @param tableView An instance of a UITableView to bind to. This view is + * not retained by the data source. + * @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 FirebaseTableViewDataSource. */ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView; + view:(UITableView *)tableView + populateCell:(UITableViewCell *(^)(UITableView *tableView, + NSIndexPath *indexPath, + FIRDataSnapshot *object))populateCell NS_DESIGNATED_INITIALIZER; -/** - * Initialize an instance of FirebaseTableViewDataSource that populates - * UITableViewCells with a - * custom model class. - * @param query A Firebase query to bind the datasource to - * @param model A custom class that FIRDataSnapshots are coerced to, defaults to - * FIRDataSnapshot if nil - * @param identifier A string to use as a CellReuseIdentifier - * @param tableView An instance of a UITableView to bind to - * @return An instance of FirebaseTableViewDataSource that populates - * UITableViewCells with a custom - * model class - */ -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - modelClass:(nullable Class)model - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView; - -/** - * Initialize an instance of FirebaseTableViewDataSource that populates - * UITableViewCells with a - * custom model class. Note that this method is used when using prototype cells, - * where the cells - * don't need to be registered in the class. - * @param query A Firebase query to bind the datasource to - * @param model A custom class that FIRDataSnapshots are coerced to, defaults to - * FIRDataSnapshot if nil - * @param identifier A string to use as a CellReuseIdentifier - * @param tableView An instance of a UITableView to bind to - * @return An instance of FirebaseTableViewDataSource that populates - * UITableViewCells with a custom - * model class - */ -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - modelClass:(nullable Class)model - prototypeReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView; - -/** - * Initialize an instance of FirebaseTableViewDataSource that populates a custom - * subclass of - * UITableViewCell with a custom model class. - * @param query A Firebase query to bind the datasource to - * @param model A custom class that FIRDataSnapshots are coerced to, defaults to - * FIRDataSnapshot if nil - * @param cell A subclass of UITableViewCell used to populate the UITableView, - * defaults to - * UITableViewCell if nil - * @param identifier A string to use as a CellReuseIdentifier - * @param tableView An instance of a UITableView to bind to - * @return An instance of FirebaseTableViewDataSource that populates a custom - * subclass of - * UITableViewCell with a custom model class - */ -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - modelClass:(nullable Class)model - cellClass:(nullable Class)cell - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView; - -/** - * Initialize an instance of FirebaseTableViewDataSource that populates a custom - * xib with a custom - * model class. - * @param query A Firebase query to bind the datasource to - * @param model A custom class that FIRDataSnapshots are coerced to, defaults to - * FIRDataSnapshot if nil - * @param nibName The name of a xib file to create the layout for a - * UITableViewCell - * @param identifier A string to use as a CellReuseIdentifier - * @param tableView An instance of a UITableView to bind to - * @return An instance of FirebaseTableViewDataSource that populates a custom - * xib with a custom - * model class - */ -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - modelClass:(nullable Class)model - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView; - -/** - * This method populates the fields of a UITableViewCell or subclass given a - * model object (or - * FIRDataSnapshot). - * @param callback A block which returns an initialized UITableViewCell - * (or subclass) and the corresponding object to populate the cell with. - */ -- (void)populateCellWithBlock:(void (^)(__kindof UITableViewCell *cell, __kindof NSObject *object))callback; +- (instancetype)initWithArray:(FirebaseArray *)array NS_UNAVAILABLE; @end diff --git a/FirebaseDatabaseUI/FirebaseTableViewDataSource.m b/FirebaseDatabaseUI/FirebaseTableViewDataSource.m index 997ebab7403..bd1ae1959cf 100644 --- a/FirebaseDatabaseUI/FirebaseTableViewDataSource.m +++ b/FirebaseDatabaseUI/FirebaseTableViewDataSource.m @@ -23,219 +23,28 @@ @import FirebaseDatabase; @interface FirebaseTableViewDataSource () -@property(strong, nonatomic) void (^populateCell) - (__kindof UITableViewCell *cell,__kindof NSObject *object); -@end - -@implementation FirebaseTableViewDataSource - -#pragma mark - FirebaseDataSource initializer methods - -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView { - return [self initWithQuery:ref - modelClass:nil - cellClass:nil - cellReuseIdentifier:identifier - view:tableView]; -} - -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - prototypeReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView { - return [self initWithQuery:ref - modelClass:nil - cellClass:nil - cellReuseIdentifier:identifier - view:tableView]; -} - -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - cellClass:(Class)cell - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView { - return [self initWithQuery:ref - modelClass:nil - cellClass:cell - cellReuseIdentifier:identifier - view:tableView]; -} - -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView { - return [self initWithQuery:ref - modelClass:nil - nibNamed:nibName - cellReuseIdentifier:identifier - view:tableView]; -} - -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(Class)model - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView { - return [self initWithQuery:ref - modelClass:model - cellClass:nil - cellReuseIdentifier:identifier - view:tableView]; -} -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(Class)model - prototypeReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView { - return [self initWithQuery:ref - modelClass:model - cellClass:nil - cellReuseIdentifier:identifier - view:tableView]; -} - -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(Class)model - cellClass:(Class)cell - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView { - return [self initWithQuery:ref - modelClass:model - cellClass:cell - cellReuseIdentifier:identifier - view:tableView]; -} - -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(Class)model - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView { - return [self initWithQuery:ref - modelClass:model - nibNamed:nibName - cellReuseIdentifier:identifier - view:tableView]; -} +@property (nonatomic, readwrite, weak) UITableView *tableView; -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView { - return [self initWithQuery:query - modelClass:nil - cellClass:nil - cellReuseIdentifier:identifier - view:tableView]; -} +@property(strong, nonatomic, readwrite) UITableViewCell *(^populateCell) + (UITableView *tableView, NSIndexPath *indexPath, FIRDataSnapshot *snap); -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - prototypeReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView { - self.hasPrototypeCell = YES; - return [self initWithQuery:query - modelClass:nil - cellClass:nil - cellReuseIdentifier:identifier - view:tableView]; -} - -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - cellClass:(Class)cell - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView { - return [self initWithQuery:query - modelClass:nil - cellClass:cell - cellReuseIdentifier:identifier - view:tableView]; -} - -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView { - return [self initWithQuery:query - modelClass:nil - nibNamed:nibName - cellReuseIdentifier:identifier - view:tableView]; -} - -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - modelClass:(Class)model - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView { - return [self initWithQuery:query - modelClass:model - cellClass:nil - cellReuseIdentifier:identifier - view:tableView]; -} - -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - modelClass:(Class)model - prototypeReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView { - self.hasPrototypeCell = YES; - return [self initWithQuery:query - modelClass:model - cellClass:nil - cellReuseIdentifier:identifier - view:tableView]; -} - -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - modelClass:(Class)model - cellClass:(Class)cell - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView { - FirebaseArray *array = [[FirebaseArray alloc] initWithQuery:query]; - self = [super initWithArray:array]; - if (self) { - if (!model) { - model = [FIRDataSnapshot class]; - } - - if (!cell) { - cell = [UITableViewCell class]; - } +@end - self.tableView = tableView; - self.modelClass = model; - self.reuseIdentifier = identifier; - self.populateCell = ^(id cell, id object) { - }; +@implementation FirebaseTableViewDataSource - if (!self.hasPrototypeCell) { - [self.tableView registerClass:cell forCellReuseIdentifier:self.reuseIdentifier]; - } - } - return self; -} +#pragma mark - FirebaseDataSource initializer methods - (instancetype)initWithQuery:(FIRDatabaseQuery *)query - modelClass:(Class)model - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView { + view:(UITableView *)tableView + populateCell:(UITableViewCell *(^)(UITableView *, + NSIndexPath *, + FIRDataSnapshot *))populateCell { FirebaseArray *array = [[FirebaseArray alloc] initWithQuery:query]; self = [super initWithArray:array]; if (self) { - if (!model) { - model = [FIRDataSnapshot class]; - } - self.tableView = tableView; - self.modelClass = model; - self.reuseIdentifier = identifier; - self.populateCell = ^(id cell, id object) { - }; - - if (!self.hasPrototypeCell) { - UINib *nib = [UINib nibWithNibName:nibName bundle:nil]; - [self.tableView registerNib:nib forCellReuseIdentifier:self.reuseIdentifier]; - } + self.populateCell = populateCell; } return self; } @@ -274,20 +83,9 @@ - (void)array:(FirebaseArray *)array didMoveObject:(id)object #pragma mark - UITableViewDataSource methods - (id)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - id cell = [self.tableView dequeueReusableCellWithIdentifier:self.reuseIdentifier - forIndexPath:indexPath]; - FIRDataSnapshot *snap = [self.items objectAtIndex:indexPath.row]; - if (![self.modelClass isSubclassOfClass:[FIRDataSnapshot class]]) { - id model = [[self.modelClass alloc] init]; - // TODO: replace setValuesForKeysWithDictionary with client API - // valueAsObject method - [model setValuesForKeysWithDictionary:snap.value]; - self.populateCell(cell, model); - } else { - self.populateCell(cell, snap); - } + UITableViewCell *cell = self.populateCell(tableView, indexPath, snap); return cell; } @@ -295,19 +93,4 @@ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger return self.count; } -- (void)populateCellWithBlock:(void (^)(__kindof UITableViewCell *cell, - __kindof NSObject *object))callback { - self.populateCell = callback; -} - -#pragma mark - Accessors - -- (void)setModelClass:(Class)modelClass { - if (modelClass == nil) { - _modelClass = [FIRDataSnapshot class]; - } else { - _modelClass = modelClass; - } -} - @end diff --git a/FirebaseDatabaseUITests/FirebaseCollectionViewDataSourceTest.m b/FirebaseDatabaseUITests/FirebaseCollectionViewDataSourceTest.m index 61a578814b9..44357ac831a 100644 --- a/FirebaseDatabaseUITests/FirebaseCollectionViewDataSourceTest.m +++ b/FirebaseDatabaseUITests/FirebaseCollectionViewDataSourceTest.m @@ -46,7 +46,7 @@ - (void)setUp { // FirebaseArray anyway. self.dataSource = [[FirebaseCollectionViewDataSource alloc] initWithQuery:(FIRDatabaseReference *)self.observable view:self.collectionView - populateCell:^UICollectionViewCell *(NSIndexPath *indexPath, UICollectionView *collectionView, FIRDataSnapshot *object) { + populateCell:^UICollectionViewCell *(UICollectionView *collectionView, NSIndexPath *indexPath, FIRDataSnapshot *object) { UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kTestReuseIdentifier forIndexPath:indexPath]; cell.accessibilityValue = object.key; return cell; diff --git a/FirebaseDatabaseUITests/FirebaseTableViewDataSourceTest.m b/FirebaseDatabaseUITests/FirebaseTableViewDataSourceTest.m index a68e207e9e6..54661b26992 100644 --- a/FirebaseDatabaseUITests/FirebaseTableViewDataSourceTest.m +++ b/FirebaseDatabaseUITests/FirebaseTableViewDataSourceTest.m @@ -44,12 +44,14 @@ - (void)setUp { self.observable = [[FUITestObservable alloc] init]; // Horrible abuse of type system, knowing that the initializer passes the observable straight to // FirebaseArray anyway. - self.dataSource = [[FirebaseTableViewDataSource alloc] initWithRef:(FIRDatabaseReference *)self.observable - cellReuseIdentifier:kTestReuseIdentifier - view:self.tableView]; - [self.dataSource populateCellWithBlock:^(__kindof UITableViewCell *_Nonnull cell, - FUIFakeSnapshot * _Nonnull object) { + self.dataSource = [[FirebaseTableViewDataSource alloc] initWithQuery:(FIRDatabaseQuery *)self.observable + view:self.tableView + populateCell:^UITableViewCell *(UITableView *tableView, + NSIndexPath *indexPath, + FIRDataSnapshot *object) { + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kTestReuseIdentifier]; cell.accessibilityValue = object.key; + return cell; }]; self.tableView.dataSource = self.dataSource; From 466cbfa4cde1ae925c66f6c04fae9f20badc526f Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Mon, 24 Oct 2016 16:40:07 -0700 Subject: [PATCH 4/4] add syntax shorthand for data sources --- .../FirebaseCollectionViewDataSource.h | 20 +++++++++++++++++++ .../FirebaseCollectionViewDataSource.m | 14 +++++++++++++ .../FirebaseTableViewDataSource.h | 20 +++++++++++++++++++ .../FirebaseTableViewDataSource.m | 14 +++++++++++++ .../FirebaseCollectionViewDataSourceTest.m | 8 ++++---- .../FirebaseTableViewDataSourceTest.m | 12 +++++------ 6 files changed, 77 insertions(+), 11 deletions(-) diff --git a/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.h b/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.h index d3650c5eaf0..d1cf036cf5b 100644 --- a/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.h +++ b/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.h @@ -83,4 +83,24 @@ NS_ASSUME_NONNULL_BEGIN @end +@interface UICollectionView (FirebaseCollectionViewDataSource) + +/** + * 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. + */ +- (FirebaseCollectionViewDataSource *)bindToQuery:(FIRDatabaseQuery *)query + populateCell:(UICollectionViewCell *(^)(UICollectionView *collectionView, + NSIndexPath *indexPath, + FIRDataSnapshot *object))populateCell __attribute__((warn_unused_result)); + +@end + NS_ASSUME_NONNULL_END diff --git a/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.m b/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.m index a8954832c00..711464e7ffd 100644 --- a/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.m +++ b/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.m @@ -84,3 +84,17 @@ - (NSInteger)collectionView:(nonnull UICollectionView *)collectionView } @end + +@implementation UICollectionView (FirebaseCollectionViewDataSource) + +- (FirebaseCollectionViewDataSource *)bindToQuery:(FIRDatabaseQuery *)query + populateCell:(UICollectionViewCell *(^)(UICollectionView *, + NSIndexPath *, + FIRDataSnapshot *))populateCell { + FirebaseCollectionViewDataSource *dataSource = + [[FirebaseCollectionViewDataSource alloc] initWithQuery:query view:self populateCell:populateCell]; + self.dataSource = dataSource; + return dataSource; +} + +@end diff --git a/FirebaseDatabaseUI/FirebaseTableViewDataSource.h b/FirebaseDatabaseUI/FirebaseTableViewDataSource.h index 114d3c747eb..cb1c9cec641 100644 --- a/FirebaseDatabaseUI/FirebaseTableViewDataSource.h +++ b/FirebaseDatabaseUI/FirebaseTableViewDataSource.h @@ -74,4 +74,24 @@ NS_ASSUME_NONNULL_BEGIN @end +@interface UITableView (FirebaseTableViewDataSource) + +/** + * 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. + */ +- (FirebaseTableViewDataSource *)bindToQuery:(FIRDatabaseQuery *)query + populateCell:(UITableViewCell *(^)(UITableView *tableView, + NSIndexPath *indexPath, + FIRDataSnapshot *object))populateCell __attribute__((warn_unused_result)); + +@end + NS_ASSUME_NONNULL_END diff --git a/FirebaseDatabaseUI/FirebaseTableViewDataSource.m b/FirebaseDatabaseUI/FirebaseTableViewDataSource.m index bd1ae1959cf..cba8739547f 100644 --- a/FirebaseDatabaseUI/FirebaseTableViewDataSource.m +++ b/FirebaseDatabaseUI/FirebaseTableViewDataSource.m @@ -94,3 +94,17 @@ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger } @end + +@implementation UITableView (FirebaseTableViewDataSource) + +- (FirebaseTableViewDataSource *)bindToQuery:(FIRDatabaseQuery *)query + populateCell:(UITableViewCell *(^)(UITableView *tableView, + NSIndexPath *indexPath, + FIRDataSnapshot *snap))populateCell { + FirebaseTableViewDataSource *dataSource = + [[FirebaseTableViewDataSource alloc] initWithQuery:query view:self populateCell:populateCell]; + self.dataSource = dataSource; + return dataSource; +} + +@end diff --git a/FirebaseDatabaseUITests/FirebaseCollectionViewDataSourceTest.m b/FirebaseDatabaseUITests/FirebaseCollectionViewDataSourceTest.m index 44357ac831a..7f787e7de2e 100644 --- a/FirebaseDatabaseUITests/FirebaseCollectionViewDataSourceTest.m +++ b/FirebaseDatabaseUITests/FirebaseCollectionViewDataSourceTest.m @@ -44,14 +44,14 @@ - (void)setUp { self.observable = [[FUITestObservable alloc] init]; // Horrible abuse of type system, knowing that the initializer passes the observable straight to // FirebaseArray anyway. - self.dataSource = [[FirebaseCollectionViewDataSource alloc] initWithQuery:(FIRDatabaseReference *)self.observable - view:self.collectionView - populateCell:^UICollectionViewCell *(UICollectionView *collectionView, NSIndexPath *indexPath, FIRDataSnapshot *object) { + self.dataSource = [self.collectionView bindToQuery:(FIRDatabaseReference *)self.observable + populateCell:^UICollectionViewCell *(UICollectionView *collectionView, + NSIndexPath *indexPath, + FIRDataSnapshot *object) { UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kTestReuseIdentifier forIndexPath:indexPath]; cell.accessibilityValue = object.key; return cell; }]; - self.collectionView.dataSource = self.dataSource; // Removing this NSLog causes the tests to crash since `numberOfItemsInSection` // actually pulls updates from the data source or something diff --git a/FirebaseDatabaseUITests/FirebaseTableViewDataSourceTest.m b/FirebaseDatabaseUITests/FirebaseTableViewDataSourceTest.m index 54661b26992..bc81871da2c 100644 --- a/FirebaseDatabaseUITests/FirebaseTableViewDataSourceTest.m +++ b/FirebaseDatabaseUITests/FirebaseTableViewDataSourceTest.m @@ -44,17 +44,15 @@ - (void)setUp { self.observable = [[FUITestObservable alloc] init]; // Horrible abuse of type system, knowing that the initializer passes the observable straight to // FirebaseArray anyway. - self.dataSource = [[FirebaseTableViewDataSource alloc] initWithQuery:(FIRDatabaseQuery *)self.observable - view:self.tableView - populateCell:^UITableViewCell *(UITableView *tableView, - NSIndexPath *indexPath, - FIRDataSnapshot *object) { + self.dataSource = [self.tableView bindToQuery:(FIRDatabaseReference *)self.observable + populateCell:^UITableViewCell *(UITableView *tableView, + NSIndexPath *indexPath, + FIRDataSnapshot *object) { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kTestReuseIdentifier]; cell.accessibilityValue = object.key; return cell; }]; - self.tableView.dataSource = self.dataSource; - + [self.observable populateWithCount:10]; }