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..d1cf036cf5b 100644 --- a/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.h +++ b/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.h @@ -46,364 +46,60 @@ 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 + * provided by the datasource. */ -- (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 - */ -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(nullable Class)model - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; - -/** - * Initialize an instance of FirebaseCollectionViewDataSource that populates - * 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 - * 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; +@property(strong, nonatomic, readonly) UICollectionViewCell *(^populateCellAtIndexPath) + (UICollectionView *collectionView, NSIndexPath *indexPath, FIRDataSnapshot *object); /** * 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 + * 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 - * a custom model class + * UICollectionViewCells with FIRDataSnapshots. */ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query - modelClass:(nullable Class)model - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; + view:(UICollectionView *)collectionView + populateCell:(UICollectionViewCell *(^)(UICollectionView *collectionView, + NSIndexPath *indexPath, + FIRDataSnapshot *object))populateCell NS_DESIGNATED_INITIALIZER; -/** - * 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; +- (instancetype)initWithArray:(FirebaseArray *)array NS_UNAVAILABLE; -/** - * 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; +@end -/** - * 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; +@interface UICollectionView (FirebaseCollectionViewDataSource) /** - * 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. + * 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. */ -- (void)populateCellWithBlock:(void (^)(__kindof UICollectionViewCell *cell, - __kindof NSObject *object))callback; +- (FirebaseCollectionViewDataSource *)bindToQuery:(FIRDatabaseQuery *)query + populateCell:(UICollectionViewCell *(^)(UICollectionView *collectionView, + NSIndexPath *indexPath, + FIRDataSnapshot *object))populateCell __attribute__((warn_unused_result)); @end diff --git a/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.m b/FirebaseDatabaseUI/FirebaseCollectionViewDataSource.m index 8c10cebc6b9..711464e7ffd 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 { + view:(UICollectionView *)collectionView + populateCell:(UICollectionViewCell *(^)(UICollectionView *, + NSIndexPath *, + FIRDataSnapshot *))populateCell { 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 { - 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(collectionView, indexPath, snap); return cell; } @@ -289,27 +83,18 @@ - (NSInteger)collectionView:(nonnull UICollectionView *)collectionView return self.count; } -- (void)populateCellWithBlock:(void (^)(__kindof UICollectionViewCell *cell, - __kindof NSObject *object))callback { - self.populateCell = callback; -} +@end -#pragma mark - Accessors +@implementation UICollectionView (FirebaseCollectionViewDataSource) -- (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; - } +- (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 6b840c71c81..cb1c9cec641 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,69 @@ 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; +@property (nonatomic, readonly, weak) 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 + * The callback used by the data source to populate the table view. */ -- (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(nullable Class)model - cellClass:(nullable Class)cell - cellReuseIdentifier:(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 - * 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 + * 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 - 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 - * 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 - */ -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - prototypeReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView; +- (instancetype)initWithArray:(FirebaseArray *)array NS_UNAVAILABLE; -/** - * 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 - */ -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView; - -/** - * 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; +@end -/** - * 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; +@interface UITableView (FirebaseTableViewDataSource) /** - * 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. + * 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. */ -- (void)populateCellWithBlock:(void (^)(__kindof UITableViewCell *cell, __kindof NSObject *object))callback; +- (FirebaseTableViewDataSource *)bindToQuery:(FIRDatabaseQuery *)query + populateCell:(UITableViewCell *(^)(UITableView *tableView, + NSIndexPath *indexPath, + FIRDataSnapshot *object))populateCell __attribute__((warn_unused_result)); @end diff --git a/FirebaseDatabaseUI/FirebaseTableViewDataSource.m b/FirebaseDatabaseUI/FirebaseTableViewDataSource.m index 997ebab7403..cba8739547f 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]; -} - -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query - cellReuseIdentifier:(NSString *)identifier - view:(UITableView *)tableView { - return [self initWithQuery:query - modelClass:nil - cellClass:nil - cellReuseIdentifier:identifier - view:tableView]; -} - -- (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]; -} +@property (nonatomic, readwrite, weak) UITableView *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]; - } +@property(strong, nonatomic, readwrite) UITableViewCell *(^populateCell) + (UITableView *tableView, NSIndexPath *indexPath, FIRDataSnapshot *snap); - 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,18 @@ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger return self.count; } -- (void)populateCellWithBlock:(void (^)(__kindof UITableViewCell *cell, - __kindof NSObject *object))callback { - self.populateCell = callback; -} +@end -#pragma mark - Accessors +@implementation UITableView (FirebaseTableViewDataSource) -- (void)setModelClass:(Class)modelClass { - if (modelClass == nil) { - _modelClass = [FIRDataSnapshot class]; - } else { - _modelClass = modelClass; - } +- (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 9645b1f1b62..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] initWithRef:(FIRDatabaseReference *)self.observable - cellReuseIdentifier:kTestReuseIdentifier - view:self.collectionView]; - [self.dataSource populateCellWithBlock:^(__kindof UICollectionViewCell *_Nonnull cell, - FUIFakeSnapshot * _Nonnull 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 a68e207e9e6..bc81871da2c 100644 --- a/FirebaseDatabaseUITests/FirebaseTableViewDataSourceTest.m +++ b/FirebaseDatabaseUITests/FirebaseTableViewDataSourceTest.m @@ -44,15 +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] initWithRef:(FIRDatabaseReference *)self.observable - cellReuseIdentifier:kTestReuseIdentifier - view:self.tableView]; - [self.dataSource populateCellWithBlock:^(__kindof UITableViewCell *_Nonnull cell, - FUIFakeSnapshot * _Nonnull 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]; }