Skip to content

Commit 01d8bb0

Browse files
committed
refactor data sources to not have a shared base class
1 parent 0b1fd5c commit 01d8bb0

File tree

9 files changed

+105
-36
lines changed

9 files changed

+105
-36
lines changed

FirebaseDatabaseUI/FUICollectionViewDataSource.h

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,26 @@ NS_ASSUME_NONNULL_BEGIN
4141
@property (nonatomic, readwrite, weak, nullable) UICollectionView *collectionView;
4242

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

5048
/**
51-
* The number of items in the data source.
49+
* The snapshots in the data source.
5250
*/
53-
@property (nonatomic, readonly) NSUInteger count;
51+
@property (nonatomic, readonly) NSArray<FIRDataSnapshot *> *items;
52+
53+
/**
54+
* A closure that should be invoked when the query encounters a fatal error.
55+
* After this is invoked, the query is no longer valid and the data source should
56+
* be recreated.
57+
*/
58+
@property (nonatomic, copy, readwrite) void (^queryErrorHandler)(NSError *);
59+
60+
/**
61+
* Returns the snapshot at the given index. Throws an exception if the index is out of bounds.
62+
*/
63+
- (FIRDataSnapshot *)snapshotAtIndex:(NSInteger)index;
5464

5565
/**
5666
* Initialize an instance of FUICollectionViewDataSource that populates

FirebaseDatabaseUI/FUICollectionViewDataSource.m

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,17 @@
2323

2424
@import FirebaseDatabase;
2525

26-
@interface FUICollectionViewDataSource ()
26+
@interface FUICollectionViewDataSource () <FUICollectionDelegate>
2727

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

30+
/**
31+
* The callback to populate a subclass of UICollectionViewCell with an object
32+
* provided by the datasource.
33+
*/
34+
@property (strong, nonatomic, readonly) UICollectionViewCell *(^populateCellAtIndexPath)
35+
(UICollectionView *collectionView, NSIndexPath *indexPath, FIRDataSnapshot *object);
36+
3037
@end
3138

3239
@implementation FUICollectionViewDataSource
@@ -40,6 +47,7 @@ - (instancetype)initWithCollection:(id<FUICollection>)collection
4047
self = [super init];
4148
if (self) {
4249
_collection = collection;
50+
_collection.delegate = self;
4351
_populateCellAtIndexPath = populateCell;
4452
}
4553
return self;
@@ -57,6 +65,14 @@ - (NSUInteger)count {
5765
return self.collection.count;
5866
}
5967

68+
- (NSArray<FIRDataSnapshot *> *)items {
69+
return self.collection.items;
70+
}
71+
72+
- (FIRDataSnapshot *)snapshotAtIndex:(NSInteger)index {
73+
return [self.collection snapshotAtIndex:index];
74+
}
75+
6076
- (void)bindToView:(UICollectionView *)view {
6177
self.collectionView = view;
6278
view.dataSource = self;
@@ -92,6 +108,12 @@ - (void)array:(FUIArray *)array didMoveObject:(id)object
92108
toIndexPath:[NSIndexPath indexPathForItem:toIndex inSection:0]];
93109
}
94110

111+
- (void)array:(id<FUICollection>)array queryCancelledWithError:(NSError *)error {
112+
if (self.queryErrorHandler != NULL) {
113+
self.queryErrorHandler(error);
114+
}
115+
}
116+
95117
#pragma mark - UICollectionViewDataSource methods
96118

97119
- (nonnull UICollectionViewCell *)collectionView:(nonnull UICollectionView *)collectionView

FirebaseDatabaseUI/FUITableViewDataSource.h

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,26 @@ NS_ASSUME_NONNULL_BEGIN
4242
@property (nonatomic, readwrite, weak, nullable) UITableView *tableView;
4343

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

5049
/**
51-
* The number of items in the data source.
50+
* The snapshots in the data source.
5251
*/
53-
@property (nonatomic, readonly) NSUInteger count;
52+
@property (nonatomic, readonly) NSArray<FIRDataSnapshot *> *items;
53+
54+
/**
55+
* A closure that should be invoked when the query encounters a fatal error.
56+
* After this is invoked, the query is no longer valid and the data source should
57+
* be recreated.
58+
*/
59+
@property (nonatomic, copy, readwrite) void (^queryErrorHandler)(NSError *);
60+
61+
/**
62+
* Returns the snapshot at the given index. Throws an exception if the index is out of bounds.
63+
*/
64+
- (FIRDataSnapshot *)snapshotAtIndex:(NSInteger)index;
5465

5566
/**
5667
* Initialize an instance of FUITableViewDataSource.

FirebaseDatabaseUI/FUITableViewDataSource.m

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
@import FirebaseDatabase;
2525

26-
@interface FUITableViewDataSource ()
26+
@interface FUITableViewDataSource () <FUICollectionDelegate>
2727

2828
@property (strong, nonatomic, readwrite) UITableViewCell *(^populateCell)
2929
(UITableView *tableView, NSIndexPath *indexPath, FIRDataSnapshot *snap);
@@ -43,6 +43,7 @@ - (instancetype)initWithCollection:(id<FUICollection>)collection
4343
self = [super init];
4444
if (self != nil) {
4545
_collection = collection;
46+
_collection.delegate = self;
4647
_populateCell = populateCell;
4748
}
4849
return self;
@@ -60,6 +61,14 @@ - (NSUInteger)count {
6061
return self.collection.count;
6162
}
6263

64+
- (NSArray<FIRDataSnapshot *> *)items {
65+
return self.collection.items;
66+
}
67+
68+
- (FIRDataSnapshot *)snapshotAtIndex:(NSInteger)index {
69+
return [self.collection snapshotAtIndex:index];
70+
}
71+
6372
- (void)bindToView:(UITableView *)view {
6473
self.tableView = view;
6574
view.dataSource = self;
@@ -103,6 +112,12 @@ - (void)array:(FUIArray *)array didMoveObject:(id)object
103112
toIndexPath:[NSIndexPath indexPathForRow:toIndex inSection:0]];
104113
}
105114

115+
- (void)array:(id<FUICollection>)array queryCancelledWithError:(NSError *)error {
116+
if (self.queryErrorHandler != NULL) {
117+
self.queryErrorHandler(error);
118+
}
119+
}
120+
106121
#pragma mark - UITableViewDataSource methods
107122

108123
- (id)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

FirebaseDatabaseUITests/FUICollectionViewDataSourceTest.m

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ - (void)setUp {
5555
return cell;
5656
}];
5757

58+
// Removing this line causes the tests to crash.
59+
NSLog(@"%lu", (unsigned long)[self.collectionView numberOfItemsInSection:0]);
60+
5861
[self.observable populateWithCount:10];
5962
}
6063

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

76+
- (void)testItReturnsSnapshots {
77+
id snap = [self.dataSource snapshotAtIndex:0];
78+
XCTAssert(snap != nil, @"expected snapshot to exist");
79+
}
80+
7381
- (void)testItPopulatesCells {
7482
UICollectionViewCell *cell = [self.dataSource collectionView:self.collectionView
7583
cellForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];

FirebaseDatabaseUITests/FUITableViewDataSourceTest.m

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ - (void)testItHasACount {
6767
XCTAssert(count == 10, @"expected data source to have 10 elements after 10 insertions, but got %lu", count);
6868
}
6969

70+
- (void)testItReturnsSnapshots {
71+
id snap = [self.dataSource snapshotAtIndex:0];
72+
XCTAssert(snap != nil, @"expected snapshot to exist");
73+
}
74+
7075
- (void)testItPopulatesCells {
7176
UITableViewCell *cell = [self.dataSource tableView:self.tableView
7277
cellForRowAtIndexPath:[NSIndexPath indexPathForRow:5 inSection:0]];

FirebaseUI.podspec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
Pod::Spec.new do |s|
22
s.name = 'FirebaseUI'
3-
s.version = '2.0.3'
3+
s.version = '3.0.0'
44
s.summary = 'UI binding libraries for Firebase.'
55
s.homepage = 'https://github.com/firebase/FirebaseUI-iOS'
66
s.license = { :type => 'Apache 2.0', :file => 'FirebaseUIFrameworks/LICENSE' }
7-
s.source = { :http => 'https://github.com/firebase/FirebaseUI-iOS/releases/download/v2.0.3/FirebaseUIFrameworks.zip' }
7+
s.source = { :http => 'https://github.com/firebase/FirebaseUI-iOS/releases/download/v3.0.0/FirebaseUIFrameworks.zip' }
88
s.author = 'Firebase'
99
s.platform = :ios
1010
s.ios.deployment_target = '8.0'

samples/swift/FirebaseUI-demo-swift/Samples/Chat/ChatViewController.swift

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -62,18 +62,15 @@ class ChatViewController: UIViewController, UICollectionViewDelegateFlowLayout {
6262
self.query = self.chatReference.queryLimited(toLast: 50)
6363

6464
self.collectionViewDataSource =
65-
FUICollectionViewDataSource(query: self.query!,
66-
view: self.collectionView,
67-
populateCell: { (view, indexPath, snap) -> UICollectionViewCell in
68-
let cell = view.dequeueReusableCell(withReuseIdentifier: ChatViewController.reuseIdentifier,
69-
for: indexPath) as! ChatCollectionViewCell
70-
let chat = Chat(snapshot: snap)!
71-
cell.populateCellWithChat(chat, user: self.user, maxWidth: self.view.frame.size.width)
72-
return cell
73-
})
74-
self.collectionView.dataSource = self.collectionViewDataSource
65+
self.collectionView.bind(to: self.query!) { (view, indexPath, snap) -> UICollectionViewCell in
66+
let cell = view.dequeueReusableCell(withReuseIdentifier: ChatViewController.reuseIdentifier,
67+
for: indexPath) as! ChatCollectionViewCell
68+
let chat = Chat(snapshot: snap)!
69+
cell.populateCellWithChat(chat, user: self.user, maxWidth: self.view.frame.size.width)
70+
return cell
71+
}
7572

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

9592
// Notification boilerplate to handle keyboard appearance/disappearance
9693
NotificationCenter.default.addObserver(self,
97-
selector: #selector(keyboardWillShow),
98-
name: NSNotification.Name.UIKeyboardWillShow,
99-
object: nil)
94+
selector: #selector(keyboardWillShow),
95+
name: NSNotification.Name.UIKeyboardWillShow,
96+
object: nil)
10097
NotificationCenter.default.addObserver(self,
101-
selector: #selector(keyboardWillHide),
102-
name: NSNotification.Name.UIKeyboardWillHide,
103-
object: nil)
98+
selector: #selector(keyboardWillHide),
99+
name: NSNotification.Name.UIKeyboardWillHide,
100+
object: nil)
104101
}
105102

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

176173
fileprivate func scrollToBottom(animated: Bool) {
177-
let count = self.collectionViewDataSource.collectionView(self.collectionView, numberOfItemsInSection: 0)
178-
let indexPath = IndexPath(row: count - 1, section: 0)
174+
let count = Int(self.collectionViewDataSource.count)
175+
guard count > 0 else { return }
176+
let indexPath = IndexPath(item: count - 1, section: 0)
179177
self.collectionView.scrollToItem(at: indexPath, at: .bottom, animated: animated)
180178
}
181179

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

188186
let width = self.view.frame.size.width
189-
let blob = self.collectionViewDataSource.object(at: UInt((indexPath as NSIndexPath).row))!
187+
let blob = self.collectionViewDataSource.snapshot(at: indexPath.item)
190188
let text = Chat(snapshot: blob)!.text
191189

192190
let rect = ChatCollectionViewCell.boundingRectForText(text, maxWidth: width)

samples/swift/Podfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
target 'FirebaseUI-demo-swift' do
22
use_frameworks!
33

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

66
target 'FirebaseUI-demo-swiftTests' do
77
inherit! :search_paths

0 commit comments

Comments
 (0)