New FUITableViewDataSource - how to use? Swift 3
The test for this latest version uses a tableView:bind: method (seems like a UITableView class extension they made) and I was able to get it to work.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let firebaseRef = FIRDatabase.database().reference().child(/*insert path for list here*/)
let query = firebaseRef.queryOrderedByKey() /*or a more sophisticated query of your choice*/
let dataSource = self.tableView.bind(to: query, populateCell: { (tableView: UITableView, indexPath: IndexPath, snapshot: FIRDataSnapshot) -> UITableViewCell in
let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier", for: indexPath)
let value = snapshot.value as! NSDictionary
let someProp = value["someProp"] as? String ?? ""
cell.textLabel?.text = someProp
return cell
})
}
Also make sure you are observing your query for changes or else the tableView won't get populated
self.query?.observe(.value, with: { snapshot in
})
Swift 3 - iOS 10 UITableView enabling swipe-to-delete
Recent FirebaseUI updates have broken the original answer.
UPDATED ANSWER:
Simply subclass FUITableViewDataSource
to implement custom UITableViewDataSource
functionality, then bind the subclass to your UITableView
.
The FUITableViewDataSource
subclass:
import UIKit
import FirebaseDatabaseUI
class EditableTableDataSource: FUITableViewDataSource {
/// Called to populate each cell in the UITableView.
typealias PopulateCellBlock = (UITableView, IndexPath, FIRDataSnapshot) -> UITableViewCell
/// Called to commit an edit to the UITableView.
typealias CommitEditBlock = (UITableView, UITableViewCellEditingStyle, IndexPath) -> Void
private let commitEditBlock: CommitEditBlock?
/// A wrapper around FUITableViewDataSource.init(query:view tableView:populateCell:), with the
/// addition of a CommitEditBlock.
public init(query: FIRDatabaseQuery,
populateCell: @escaping PopulateCellBlock,
commitEdit: @escaping CommitEditBlock)
{
commitEditBlock = commitEdit
super.init(collection: FUIArray.init(query: query), populateCell: populateCell)
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
override func tableView(_ tableView: UITableView,
commit editingStyle: UITableViewCellEditingStyle,
forRowAt indexPath: IndexPath)
{
if (commitEditBlock != nil) {
commitEditBlock!(tableView, editingStyle, indexPath)
}
}
}
extension UITableView {
/// Creates a data source, binds it to the table view, and returns it. Note that this is the
/// `EditableTableViewDataSource` equivalent of the
/// `FUITableViewDataSource.bind(to:populateCell:)` method.
///
/// - parameters:
/// - to: The Firebase query to bind to.
/// - populateCell: A closure that's called to populate each cell.
/// - commitEdit: A closure that's called when the user commits some kind of edit. Maps to
/// `tableView(:commit:forRowAt:)`.
func bind(to query: FIRDatabaseQuery,
populateCell: @escaping EditableTableDataSource.PopulateCellBlock,
commitEdit: @escaping EditableTableDataSource.CommitEditBlock)
-> EditableTableDataSource
{
let dataSource = EditableTableDataSource(query: query,
populateCell: populateCell,
commitEdit: commitEdit)
dataSource.bind(to: self)
return dataSource
}
}
And usage:
import UIKit
import FirebaseDatabaseUI
class ScheduleViewController: UITableViewController {
private let TAG = String(describing: ScheduleViewController.self)
private var dataSource: FUITableViewDataSource!
private var dataManager: DataManager!
override func viewDidLoad() {
super.viewDidLoad()
dataManager = AppManager.defaultInstance.dataManager()
dataSource = tableView.bind(
to: dataManager.scheduledHabitsQuery(),
populateCell: populateCellBlock(),
commitEdit: commitEditBlock())
}
// MARK: TableView Data Source
func populateCellBlock() -> EditableTableDataSource.PopulateCellBlock {
return { tableView, indexPath, snapshot in
let cell = ScheduledHabitTableViewCell.from(tableView: tableView, at: indexPath)
cell.set(habit: ScheduledHabit(fromSnapshot: snapshot))
return cell
}
}
func commitEditBlock() -> EditableTableDataSource.CommitEditBlock {
return { tableView, editingStyle, indexPath in
if (editingStyle != .delete) {
return
}
// Delete the data from Firebase.
let snapshot = self.dataSource.snapshot(at: indexPath.row)
self.dataManager.moveToTrash(ScheduledHabit(fromSnapshot: snapshot))
// Deleting the table view row is done automatically by the FirebaseUI data source.
}
}
// MARK: - Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
}
}
ORIGINAL ANSWER:
The solution is to subclass FUITableViewDataSource
and override the UITableViewDataSource
methods you want. Everything worked perfectly after that.
import UIKit
import FirebaseDatabaseUI
class FUIEditableTableViewDataSource: FUITableViewDataSource {
/// Called to populate each cell in the UITableView.
typealias PopulateCellBlock = (UITableView, IndexPath, FIRDataSnapshot) -> UITableViewCell
/// Called to commit an edit to the UITableView.
typealias CommitEditBlock = (UITableView, UITableViewCellEditingStyle, IndexPath) -> Void
private let commitEditBlock: CommitEditBlock?
/// A wrapper around FUITableViewDataSource.init(query:view tableView:populateCell:), with the
/// addition of a CommitEditBlock.
public init(query: FIRDatabaseQuery,
tableView: UITableView,
populateCell: @escaping PopulateCellBlock,
commitEdit: @escaping CommitEditBlock)
{
commitEditBlock = commitEdit
super.init(query: query, view: tableView, populateCell: populateCell)
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
override func tableView(_ tableView: UITableView,
commit editingStyle: UITableViewCellEditingStyle,
forRowAt indexPath: IndexPath)
{
if (commitEditBlock != nil) {
commitEditBlock!(tableView, editingStyle, indexPath)
}
}
}
What is the iOS version of firebase list adapter?
The equivalent is:
FUITableViewDataSource
Data source to bind a Firebase query to a UITableView
Equivalent for FirebaseRecyclerAdapter:
FUICollectionViewDataSource
Data source to bind a Firebase query to a UICollectionView
more info here:
FirebaseUI for IOS
Accessing a variable outside closure Swift3
this is what should happens because observe function is asynchronous and the rest of your code is synchronous, in addition if you remove the optional unwrap from requestPostArray?
you will get a nil exception because the async task needs time to get executed so the compiler will execute the snyc task before it.
basically what you have to do is the following
else {
ref.child("Request Posts").observe(.value, with: { (snapshot) in
let count = Int(snapshot.childrenCount)
// Request Post database is empty
if count == 0 {
cell.nameLabel.text = "No requests so far."
cell.userNameLabel.isHidden = true
cell.numberOfRequestsLabel.isHidden = true
}
// Request Post data is populated
else {
var requestPostArray: [RequestPost]? = []
self.ref.child("Request Posts").observe(.value, with: { (snapshot) in
if let result = snapshot.children.allObjects as? [FIRDataSnapshot] {
for child in result {
let post = RequestPost(snapshot: child)
requestPostArray?.append(post)
}
}
else {
print("No Result")
}
print("RequestPostArray size = \(requestPostArray?.count ?? 90)")
cell.nameLabel.text = self.requestPostArray?[indexPath.row].name
cell.userNameLabel.text = self.requestPostArray?[indexPath.row].name
cell.numberOfRequestsLabel.text = self.requestPostArray?[indexPath.row].name
})
}
})
}
another advice think about using singleton so you can gain the reuse of your object and you will not invoke the database several time at the same method like you are doing now.
Visual Studio Find dialog non-standard regular expressions
Maybe for the same reason that Perl, Emacs, extended Regexps all have different 'standard' syntaxes (albeit mostly similar): they were all developed with different requirements. Emacs doesn't seem to offer \d
for instance for matching numeric digits. (arguably \d
isn't 'standard', but is reasonably widely supported, so one might think that is was standard)
There's support for bidirectional and other unicode characters offers more control than what's available in POSIX, plus there's the rather useful :i
and :q
as shortcuts for C/C++ identifiers and quoted strings. So the different syntax presumably grew out of the domain-specific requirements of VS.Net. More on the different things supported here.
I agree that it is an annoyance to have a different syntax, but I also find it annoying to remember to type [:digit:]
rather than \d
when I'm emacs.
Related Topics
Firebase Sms Verification on iOS - 'Token Mismatch'
Can You Evaluate a String in Swift
Programmatically Create an Nsviewcontroller Without an Xib in Swift 3
Swift Conditional Conformances with Generic Type
Uisearchbar's Set_Cancelbuttontext: Ivar Is Prohibited
Ibdesignable and Uitableviewcell
Xcode UI Test:Accessibility Query Fail on Uitableviewcell
Swift Codable - Parse JSON Array Which Can Contain Different Data Type
Getting a Segmentation Fault: 11 with Swift 5.2 When Using Filemanager.Default.Currentdirectorypath
From Any Utf-16 Offset, Find the Corresponding String.Index That Lies on a Character Boundary
Passing and Storing Closures/Callbacks in Swift
Swift Combine: Using Timer Publisher in an Observable Object
Realmswift + Multiple Predicate
Convert to Latest Swift Syntax' Breaks the Build Even When There Are No Changes
How to Integrate Uisearchcontroller with Swiftui
How to Set Interactive Push Notifications on iOS8