Skip to content

Commit

Permalink
refactor data sources to not have a shared base class
Browse files Browse the repository at this point in the history
  • Loading branch information
morganchen12 committed Feb 10, 2017
1 parent 0b1fd5c commit 01d8bb0
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 36 deletions.
22 changes: 16 additions & 6 deletions FirebaseDatabaseUI/FUICollectionViewDataSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,26 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readwrite, weak, nullable) UICollectionView *collectionView;

/**
* The callback to populate a subclass of UICollectionViewCell with an object
* provided by the datasource.
* The number of items in the data source.
*/
@property (strong, nonatomic, readonly) UICollectionViewCell *(^populateCellAtIndexPath)
(UICollectionView *collectionView, NSIndexPath *indexPath, FIRDataSnapshot *object);
@property (nonatomic, readonly) NSUInteger count;

/**
* The number of items in the data source.
* The snapshots in the data source.
*/
@property (nonatomic, readonly) NSUInteger count;
@property (nonatomic, readonly) NSArray<FIRDataSnapshot *> *items;

/**
* A closure that should be invoked when the query encounters a fatal error.
* After this is invoked, the query is no longer valid and the data source should
* be recreated.
*/
@property (nonatomic, copy, readwrite) void (^queryErrorHandler)(NSError *);

/**
* Returns the snapshot at the given index. Throws an exception if the index is out of bounds.
*/
- (FIRDataSnapshot *)snapshotAtIndex:(NSInteger)index;

/**
* Initialize an instance of FUICollectionViewDataSource that populates
Expand Down
24 changes: 23 additions & 1 deletion FirebaseDatabaseUI/FUICollectionViewDataSource.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,17 @@

@import FirebaseDatabase;

@interface FUICollectionViewDataSource ()
@interface FUICollectionViewDataSource () <FUICollectionDelegate>

@property (nonatomic, readonly, nonnull) id<FUICollection> collection;

/**
* The callback to populate a subclass of UICollectionViewCell with an object
* provided by the datasource.
*/
@property (strong, nonatomic, readonly) UICollectionViewCell *(^populateCellAtIndexPath)
(UICollectionView *collectionView, NSIndexPath *indexPath, FIRDataSnapshot *object);

@end

@implementation FUICollectionViewDataSource
Expand All @@ -40,6 +47,7 @@ - (instancetype)initWithCollection:(id<FUICollection>)collection
self = [super init];
if (self) {
_collection = collection;
_collection.delegate = self;
_populateCellAtIndexPath = populateCell;
}
return self;
Expand All @@ -57,6 +65,14 @@ - (NSUInteger)count {
return self.collection.count;
}

- (NSArray<FIRDataSnapshot *> *)items {
return self.collection.items;
}

- (FIRDataSnapshot *)snapshotAtIndex:(NSInteger)index {
return [self.collection snapshotAtIndex:index];
}

- (void)bindToView:(UICollectionView *)view {
self.collectionView = view;
view.dataSource = self;
Expand Down Expand Up @@ -92,6 +108,12 @@ - (void)array:(FUIArray *)array didMoveObject:(id)object
toIndexPath:[NSIndexPath indexPathForItem:toIndex inSection:0]];
}

- (void)array:(id<FUICollection>)array queryCancelledWithError:(NSError *)error {
if (self.queryErrorHandler != NULL) {
self.queryErrorHandler(error);
}
}

#pragma mark - UICollectionViewDataSource methods

- (nonnull UICollectionViewCell *)collectionView:(nonnull UICollectionView *)collectionView
Expand Down
21 changes: 16 additions & 5 deletions FirebaseDatabaseUI/FUITableViewDataSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,26 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readwrite, weak, nullable) UITableView *tableView;

/**
* The callback used by the data source to populate the table view.
* The number of items in the data source.
*/
@property (strong, nonatomic, readonly) UITableViewCell *(^populateCell)
(UITableView *tableView, NSIndexPath *indexPath, FIRDataSnapshot *snap);
@property (nonatomic, readonly) NSUInteger count;

/**
* The number of items in the data source.
* The snapshots in the data source.
*/
@property (nonatomic, readonly) NSUInteger count;
@property (nonatomic, readonly) NSArray<FIRDataSnapshot *> *items;

/**
* A closure that should be invoked when the query encounters a fatal error.
* After this is invoked, the query is no longer valid and the data source should
* be recreated.
*/
@property (nonatomic, copy, readwrite) void (^queryErrorHandler)(NSError *);

/**
* Returns the snapshot at the given index. Throws an exception if the index is out of bounds.
*/
- (FIRDataSnapshot *)snapshotAtIndex:(NSInteger)index;

/**
* Initialize an instance of FUITableViewDataSource.
Expand Down
17 changes: 16 additions & 1 deletion FirebaseDatabaseUI/FUITableViewDataSource.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

@import FirebaseDatabase;

@interface FUITableViewDataSource ()
@interface FUITableViewDataSource () <FUICollectionDelegate>

@property (strong, nonatomic, readwrite) UITableViewCell *(^populateCell)
(UITableView *tableView, NSIndexPath *indexPath, FIRDataSnapshot *snap);
Expand All @@ -43,6 +43,7 @@ - (instancetype)initWithCollection:(id<FUICollection>)collection
self = [super init];
if (self != nil) {
_collection = collection;
_collection.delegate = self;
_populateCell = populateCell;
}
return self;
Expand All @@ -60,6 +61,14 @@ - (NSUInteger)count {
return self.collection.count;
}

- (NSArray<FIRDataSnapshot *> *)items {
return self.collection.items;
}

- (FIRDataSnapshot *)snapshotAtIndex:(NSInteger)index {
return [self.collection snapshotAtIndex:index];
}

- (void)bindToView:(UITableView *)view {
self.tableView = view;
view.dataSource = self;
Expand Down Expand Up @@ -103,6 +112,12 @@ - (void)array:(FUIArray *)array didMoveObject:(id)object
toIndexPath:[NSIndexPath indexPathForRow:toIndex inSection:0]];
}

- (void)array:(id<FUICollection>)array queryCancelledWithError:(NSError *)error {
if (self.queryErrorHandler != NULL) {
self.queryErrorHandler(error);
}
}

#pragma mark - UITableViewDataSource methods

- (id)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
Expand Down
8 changes: 8 additions & 0 deletions FirebaseDatabaseUITests/FUICollectionViewDataSourceTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ - (void)setUp {
return cell;
}];

// Removing this line causes the tests to crash.
NSLog(@"%lu", (unsigned long)[self.collectionView numberOfItemsInSection:0]);

[self.observable populateWithCount:10];
}

Expand All @@ -70,6 +73,11 @@ - (void)testItHasACount {
XCTAssert(count == 10, @"expected data source to have 10 elements after 10 insertions, but got %lu", count);
}

- (void)testItReturnsSnapshots {
id snap = [self.dataSource snapshotAtIndex:0];
XCTAssert(snap != nil, @"expected snapshot to exist");
}

- (void)testItPopulatesCells {
UICollectionViewCell *cell = [self.dataSource collectionView:self.collectionView
cellForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
Expand Down
5 changes: 5 additions & 0 deletions FirebaseDatabaseUITests/FUITableViewDataSourceTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ - (void)testItHasACount {
XCTAssert(count == 10, @"expected data source to have 10 elements after 10 insertions, but got %lu", count);
}

- (void)testItReturnsSnapshots {
id snap = [self.dataSource snapshotAtIndex:0];
XCTAssert(snap != nil, @"expected snapshot to exist");
}

- (void)testItPopulatesCells {
UITableViewCell *cell = [self.dataSource tableView:self.tableView
cellForRowAtIndexPath:[NSIndexPath indexPathForRow:5 inSection:0]];
Expand Down
4 changes: 2 additions & 2 deletions FirebaseUI.podspec
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
Pod::Spec.new do |s|
s.name = 'FirebaseUI'
s.version = '2.0.3'
s.version = '3.0.0'
s.summary = 'UI binding libraries for Firebase.'
s.homepage = 'https://github.com/firebase/FirebaseUI-iOS'
s.license = { :type => 'Apache 2.0', :file => 'FirebaseUIFrameworks/LICENSE' }
s.source = { :http => 'https://github.com/firebase/FirebaseUI-iOS/releases/download/v2.0.3/FirebaseUIFrameworks.zip' }
s.source = { :http => 'https://github.com/firebase/FirebaseUI-iOS/releases/download/v3.0.0/FirebaseUIFrameworks.zip' }
s.author = 'Firebase'
s.platform = :ios
s.ios.deployment_target = '8.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,15 @@ class ChatViewController: UIViewController, UICollectionViewDelegateFlowLayout {
self.query = self.chatReference.queryLimited(toLast: 50)

self.collectionViewDataSource =
FUICollectionViewDataSource(query: self.query!,
view: self.collectionView,
populateCell: { (view, indexPath, snap) -> UICollectionViewCell in
let cell = view.dequeueReusableCell(withReuseIdentifier: ChatViewController.reuseIdentifier,
for: indexPath) as! ChatCollectionViewCell
let chat = Chat(snapshot: snap)!
cell.populateCellWithChat(chat, user: self.user, maxWidth: self.view.frame.size.width)
return cell
})
self.collectionView.dataSource = self.collectionViewDataSource
self.collectionView.bind(to: self.query!) { (view, indexPath, snap) -> UICollectionViewCell in
let cell = view.dequeueReusableCell(withReuseIdentifier: ChatViewController.reuseIdentifier,
for: indexPath) as! ChatCollectionViewCell
let chat = Chat(snapshot: snap)!
cell.populateCellWithChat(chat, user: self.user, maxWidth: self.view.frame.size.width)
return cell
}

// FirebaseArray has a delegate method `childAdded` that could be used here,
// FUIArray has a delegate method `childAdded` that could be used here,
// but unfortunately FirebaseCollectionViewDataSource uses the FUICollection
// delegate methods to update its own internal state, so in order to scroll
// on new insertions we still need to use the query directly.
Expand All @@ -94,13 +91,13 @@ class ChatViewController: UIViewController, UICollectionViewDelegateFlowLayout {

// Notification boilerplate to handle keyboard appearance/disappearance
NotificationCenter.default.addObserver(self,
selector: #selector(keyboardWillShow),
name: NSNotification.Name.UIKeyboardWillShow,
object: nil)
selector: #selector(keyboardWillShow),
name: NSNotification.Name.UIKeyboardWillShow,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(keyboardWillHide),
name: NSNotification.Name.UIKeyboardWillHide,
object: nil)
selector: #selector(keyboardWillHide),
name: NSNotification.Name.UIKeyboardWillHide,
object: nil)
}

@objc fileprivate func didTapSend(_ sender: AnyObject) {
Expand Down Expand Up @@ -174,8 +171,9 @@ class ChatViewController: UIViewController, UICollectionViewDelegateFlowLayout {
}

fileprivate func scrollToBottom(animated: Bool) {
let count = self.collectionViewDataSource.collectionView(self.collectionView, numberOfItemsInSection: 0)
let indexPath = IndexPath(row: count - 1, section: 0)
let count = Int(self.collectionViewDataSource.count)
guard count > 0 else { return }
let indexPath = IndexPath(item: count - 1, section: 0)
self.collectionView.scrollToItem(at: indexPath, at: .bottom, animated: animated)
}

Expand All @@ -186,7 +184,7 @@ class ChatViewController: UIViewController, UICollectionViewDelegateFlowLayout {
let heightPadding: CGFloat = 16

let width = self.view.frame.size.width
let blob = self.collectionViewDataSource.object(at: UInt((indexPath as NSIndexPath).row))!
let blob = self.collectionViewDataSource.snapshot(at: indexPath.item)
let text = Chat(snapshot: blob)!.text

let rect = ChatCollectionViewCell.boundingRectForText(text, maxWidth: width)
Expand Down
2 changes: 1 addition & 1 deletion samples/swift/Podfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
target 'FirebaseUI-demo-swift' do
use_frameworks!

pod 'FirebaseUI', :podspec => 'https://raw.githubusercontent.com/firebase/FirebaseUI-iOS/master/FirebaseUI.podspec'
pod 'FirebaseUI', :podspec => '../../FirebaseUI.podspec'

target 'FirebaseUI-demo-swiftTests' do
inherit! :search_paths
Expand Down

0 comments on commit 01d8bb0

Please sign in to comment.