RJH
RJH

Reputation: 358

Incorrect Firebase data return

I have the following Swift & Firebase code which returns the data as expected (initially) but if the data is changed by another user and the current user goes back into the table, it shows the old data. It only updates with the new data if the user goes out and back into the table where it then shows the correct data.

It's as if the data is cached but I have persistence disabled):

import UIKit
import Firebase

class Agent_NewRequests: UITableViewController {

    let custom = custom()
    var dbConnector = FIRDatabase.database().reference()

    var userID:String!
    var searchResults = [agentNewRequests]()
    var requestID:String!

    var loadingOverlay = LoadingOverlay()


    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewWillAppear(animated: Bool) {
        self.searchResults.removeAll(keepCapacity: false)
        FIRAuth.auth()!.addAuthStateDidChangeListener() { (auth, user) in
            if user != nil {
                // user authenticated
                self.userID = user!.uid
                self.retrieveRequests()
            } else {
                // No user is signed in
                self.custom.showLogin(self.self)
            }
        }
    }

    override func viewWillDisappear(animated: Bool) {
        dbConnector.removeAllObservers()
    }

    func retrieveRequests() {
        if self.userID == "" {
            loadingOverlay.hideOverlayView()
            // todo - show error
            return
        }

        loadingOverlay.showOverlay(self.view)
        var timeLastUpdated = ""
        self.searchResults.removeAll(keepCapacity: false)

        let userRef = dbConnector.child("requests/\(self.userID)")
        userRef.queryEqualToValue("Submitted", childKey: "status")
        userRef.observeSingleEventOfType(.ChildAdded, withBlock: { snapshot in
            guard snapshot.exists() else {
                // No data found, handle error otherwise will crash
                self.checkTable()
                self.loadingOverlay.hideOverlayView()
                return
            }

            if let _:String = snapshot.value!["status"] as? String { } else {
                self.checkTable()
                self.loadingOverlay.hideOverlayView()
                return
            }

            let status = snapshot.value!["status"] as! String

            if status != "Submitted" {
                self.checkTable()
                return
            }

            let key = snapshot.key as String
            let tenantID = snapshot.value!["tenant_id"] as! String
            let address = snapshot.value!["address"] as! String
            let desc = snapshot.value!["description"] as! String
            let timeUpdate:Int = snapshot.value!["time_updated"] as! Int
            let priority = snapshot.value!["priority"] as! Int

            let dateFormat = NSDateFormatter()
            dateFormat.dateStyle = NSDateFormatterStyle.LongStyle
            dateFormat.timeStyle = NSDateFormatterStyle.ShortStyle

            if timeUpdate == 0 { // if it has never been updated, use time created instead for lastupdated
                let cTimeInterval = snapshot.value!["time_created"] as? NSTimeInterval
                let updateTime = NSDate(timeIntervalSince1970: cTimeInterval! / 1000)
                timeLastUpdated = dateFormat.stringFromDate(updateTime)
            } else {
                let uTimeInterval = snapshot.value!["time_updated"] as? NSTimeInterval
                let updateTime = NSDate(timeIntervalSince1970: uTimeInterval! / 1000)
                timeLastUpdated = dateFormat.stringFromDate(updateTime)

            }
            var imgData:String = ""

            self.searchResults += [agentNewRequests(requestID: key, tenantID: tenantID, address: address, description: desc, lastUpdated: timeLastUpdated, mediaData: mediaData, priority: priority)]
            dispatch_async(dispatch_get_main_queue()){
                self.checkTable()
            }
        }) { error in
            print(error.description)
            self.loadingOverlay.hideOverlayView()
        }
    }


    func checkTable() {
        if (self.searchResults.count > 0) {
            self.searchResults = self.searchResults.reverse()
            self.tableView.reloadData()
            self.loadingOverlay.hideOverlayView()
            // remove any previous signs of errorMessageLabel
            self.tableView.backgroundView = nil
            self.tableView.separatorColor = custom.UIColorFromRGB(0x574987, alphaValue: 1)
            self.tableView.separatorStyle = UITableViewCellSeparatorStyle.SingleLine
        } else {
            self.tableView.reloadData()
            self.loadingOverlay.hideOverlayView()
            // Display a message that the table is empty
            let errorMessageLabel = UILabel()
            errorMessageLabel.frame = CGRectMake(0, 0, self.tableView.bounds.width, (self.tableView.bounds.height + 100))
            errorMessageLabel.text = "No new requests found"
            errorMessageLabel.numberOfLines = 1
            errorMessageLabel.textColor = UIColor.blackColor()
            errorMessageLabel.textAlignment = NSTextAlignment.Center
            errorMessageLabel.sizeToFit()
            self.tableView.backgroundView = errorMessageLabel
            self.tableView.separatorColor = UIColor.clearColor()
            self.tableView.separatorStyle = UITableViewCellSeparatorStyle.SingleLine
        }
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell:Agent_NewRequests_Cell = self.tableView.dequeueReusableCellWithIdentifier("requestCell")
            as! Agent_NewRequests_Cell
        cell.idLabel.text = searchResults[indexPath.row].description
        cell.updatedLabel.text = searchResults[indexPath.row].lastUpdated
        cell.addressLabel.text = searchResults[indexPath.row].address

        return cell
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return searchResults.count
    }

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        requestID = searchResults[indexPath.row].requestID
        self.performSegueWithIdentifier("newToRequestCard", sender: indexPath);
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
        if (segue.identifier == "newToRequestCard") {
            let requestCard = segue.destinationViewController as! Agent_Request_Card;
            requestCard.toPass_requestID = self.requestID
            requestCard.toPass_agentID = self.userID
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

If I change it from .ObserveSingleEventOfType to .ObserveEventType it works as expected BUT... if the data is deleted elsewhere and there is no other data, the UI just sits listening for updates and I don't want that, I need the user to be told there is no data with a UI update (which never happens)

Upvotes: 3

Views: 745

Answers (1)

Bryan
Bryan

Reputation: 1365

Use ObserveEventType instead of ObserveSingleEventOfType and just check whether or not the data is present. If it isn't, update the UI with a message. If it is, continue as normal.

Upvotes: 1

Related Questions