简体   繁体   中英

How to reload UITableView data after Firebase finishes dowload of user data?

so I have a problem with firebase since it's async and I don't know how to work with that properly. My application has feed of products for sale, which I'm getting from firebase database and firebase storage(pictures). The problem is that I don't know when or how to reload my UITableView to get all the data without getting nil error. And it's even more complicated, because first I need to get my salePost information from firebase and only after that I can obtain user Information which is also in tableview cell.

This is how I getting my salePosts

    func getSalePosts() -> [SalePost]{

    var salePosts = [SalePost]()

    FIR_DATABASE_SALE_POSTS.queryLimitedToFirst(NUMBER_OF_LOADED_POSTS).observeEventType(.Value, withBlock: { (snapshot) in

        for snap in snapshot.children{

            let imgString = snap.value["image"] as! String!
            let imgNSURL = NSURL(string: imgString)
            let imgNSDATA = NSData(contentsOfURL: imgNSURL!)

            let downloadedImg = UIImage(data: imgNSDATA!)

            let newSalePost = SalePost(title: snap.value["title"] as! String!,
                userUID: snap.value["authorUID"] as! String!,
                postBody: snap.value["body"] as! String!,
                amountAvailable: snap.value["amountAvailable"] as! String!,
                unit: snap.value["unit"] as! String!,
                price: snap.value["price"] as! String!,
                image: downloadedImg!)

            salePosts.append(newSalePost)
            print("num of posts \(salePosts.count)")
        }

    }) { (error) in
            print(error.localizedDescription)
    }

    return salePosts
}

And this is func which is getting UserInfo (I will get the "userUID" from salePost object)

    func getProducer(userUID:String) -> Producer{


    var newProducer:Producer?

    FIR_DATABASE_USERS.child(userUID).observeEventType(.Value, withBlock: { (snap) in

        print(snap.description)

        let imgString = snap.value!["profilePic"] as! String!
        let imgNSURL = NSURL(string: imgString)
        let imgNSDATA = NSData(contentsOfURL: imgNSURL!)
        let downloadedImg = UIImage(data: imgNSDATA!)


        let someProducer = Producer(
            displayName: snap.value!["displayName"] as! String!,
            address: snap.value!["address"] as! String!,
            mobile: snap.value!["mobile"] as! String!,
            email: snap.value!["email"] as! String!,
            password: "",
            bio: snap.value!["bio"] as! String!,
            profilePic: downloadedImg!,
            openingHour: snap.value!["openingHour"] as! String!,
            closingHour: snap.value!["closingHour"] as! String!)

        newProducer = someProducer
        print(newProducer?.description)

        }) { (error) in
            print(error.localizedDescription)
    }

    return newProducer!
}

So as I said, I don't know when, where and how to call these functions (in my feed controller) to make it "synchronous" and to get all that data to the tableview Cells right. I will appreciate every help. I tried google it and even find it here, but nothing helped me.

Once you created all your salePosts you should call tableView.reloadData() . So right after you loop to create where you append your newSalePost to your salePosts . Since this is an asynchronous call returning your salePosts at the end of your function is useless.

I'm assuming that you have an attribute tableView of your viewController and you set the delegate and datasource of your tableView to be your viewController .

Do not forget to call tableView.reloadData() on the main thread.

eg: Dispatch.main.async { self.tableView.reloadData() } .

For future users seeing this post, you can also use Dispatch group to handle the async property of data retrieval from Firebase. For more on the working of dispatch groups you can read Dispatch Groups in Swift 3 . The syntax is more or less same in Swift 4 as well. This is how i have implemented dispatch for my project with a tableview.

var anEmptyArray: [String] = []
var dbRef: DatabaseReference!

@IBOutlet weak var myTable: UITableView!

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

func retrieveDataFromDatabase() {
    dbRef = Database.database().reference().child("user")
    dbRef.observe(.value, with: { snapshot in
        let group = DispatchGroup()
        let enumerator = snapshot.children

        while let rest = enumerator.nextObject() as? DataSnapshot {
            group.enter()
            self.categories.append(rest.value as! String)
            group.leave()
        }
        group.notify(queue: .main) {
            self.categoryTable.reloadData()
        }
    })

}

I have used snapshot.children, because of how i have structured my data. How you are getting the snapshot will depend on the structure you have. The dispatch group has to be used within the dbRef.observe closure.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM