The summary of my problem is; when the tableView.reloadData()
is called upon firestore's local changes on the first time the view loads up it works and updates as it supposed to. However, after I switch forth and back with other viewControllers, although initially on viewDidAppear()
tableView get's reloaded, upon local changes it no longer does so.
I've included a simpler version of my project to better explain and to make it reproducable;
Class Item
let db = Firestore.firestore()
static var list = [String:[String:Any]]()
static var listenerSet = Bool()
static var listener: ListenerRegistration!
func setListener(completion: @escaping (String) -> Void) {
if !Item.listenerSet {
print("Attaching item document listener.")
Item.listener = db.collection("Items").document("default").addSnapshotListener({ (document, error) in
let source = document!.metadata.hasPendingWrites ? "Local" : "Server"
print("Updating item data from the \(source).")
Item.listenerSet = true
Item.list = document?.get("List") as! [String:[String:Any]]
completion("Item data is set")
})
} else {
completion("Item listener already exists")
}
}
func add(itemID:String) {
let itemRef = db.collection("Items").document("default")
itemRef.setData([
"List": [
itemID : [
"Count": FieldValue.increment(1.0),
]]
], merge:true)
}
FirstViewController:UIViewController
let item = Item()
var itemList = [[String:Any]]()
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var switchBar: UISegmentedControl!
override func viewDidLoad() {
super.viewDidLoad()
// Setting the table views
tableView.delegate = self
tableView.dataSource = self
}
override func viewDidAppear(_ animated: Bool) {
print("View Did appear") // prints OK
item.setListener() { (result) in
print(result)
loadData()
}
}
func loadData() {
itemList.removeAll()
var counter = 0
for (id,data) in Item.list {
itemList.append(data)
itemList[counter]["ID"] = id
counter += 1
}
tableView.reloadData()
}
@IBAction func switchBarChanged(_ sender: UISegmentedControl) {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
switch switchBar.selectedSegmentIndex {
case 1:
let vc = storyBoard.instantiateViewController(identifier: "secondViewController")
show(vc, sender: self)
default:
break
}
}
Extension FirstViewController: UITableViewDataSource,UITableViewDelegate
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("These are items:\(itemList)")
print(itemList.count)
print(tableView.bounds.height)
return itemList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell") as! ItemCell
let itemID = itemList[indexPath.row]["ID"] as! String
let itemName = itemList[indexPath.row]["Name"] as! String
let itemCount = itemList[indexPath.row]["Count"] as! Double
cell.itemID = itemID
cell.itemName.text = itemName
cell.itemCount.text = String(itemCount)
print("Items within the tableView \(itemList)") // prints only in the first run whenever there is an upload, or when refreshed.
return cell
}
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let add = UIContextualAction(style: .normal, title: "Add", handler: { (action, view, completionHandler) in
item.add(itemID:(itemList[indexPath.row]["ID"] as! String))
completionHandler(true)
})
add.image = UIImage(systemName: "plus")
let configuration = UISwipeActionsConfiguration(actions: [add])
configuration.performsFirstActionWithFullSwipe = true
return configuration
}
Class ItemCell:UITableViewCell
var itemID = String()
@IBOutlet weak var itemName: UILabel!
@IBOutlet weak var itemCount: UILabel!
SecondViewController:UIViewController
@IBOutlet weak var switchBar: UISegmentedControl!
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func switchBarChanged(_ sender: UISegmentedControl) {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
switch switchBar.selectedSegmentIndex {
case 0:
let vc = storyBoard.instantiateViewController(identifier: "firstViewController")
show(vc, sender: self)
default:
break
}
}
Now this is the flow I'm having issue on;
- Application loads,
FirstViewController
loads,viewDidAppear
kicks in.tableView
loads. - When swiped right, the value in firestore server increments by one, snapshot listener kicks in, tableview reloads and everything works as it supposed to be.
- After I switch to
SecondViewController
and come back toFirstViewController
,viewDidAppear
kicks intableView
loads. - This time however, when I swipe right again, the value in firestore server still increments by one and the snapshot listener kicks in, updating the
Item.list
.static var ItemList
gets updated, and tableView does reload, however this time, onlynumberOfRowsInSection
method works as it prints the count and updated itemList, then nothing happenscellForRowAt
doesn't work and rows don't get updated. - Now at this stage if I go
SecondViewController
and comeback toFirstViewController
the rows are updated, but when swiped right still no avail.
What am I missing here ? Thanks all for your replies.