Chris_1983_Norway
Chris_1983_Norway

Reputation: 399

How to complete function before ViewDidLoad

I'm fairly certain my function to get data from Firebase is working correctly, however I can't display the data in the ViewController. It seems the View is rendered before the function is completed.

I need help figuring out how to run the function before the view is rendered.

This is the code in the viewController

import UIKit
import Firebase
import Kingfisher

class activityVC: UIViewController {

    // Variables passed from feedVC
    var activityId = ""

    @IBOutlet weak var distance: UILabel!
    @IBOutlet weak var time: UILabel!
    @IBOutlet weak var elevation: UILabel!
    @IBOutlet weak var kills: UILabel!
    @IBOutlet weak var sightings: UILabel!
    @IBOutlet weak var ration_shot_sightings: UILabel!
    @IBOutlet weak var activityImageView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Get userdata from Firebase
        DataService.instance.getActivityData(activityId: activityId) { (activityData) in
            print("activity data dump in ViewController")
            dump(activityData)
            if activityData.isEmpty == false {
                print("Data is coming")
                // if data exist populate textfields with information from database
                self.kills.text = activityData[0].name
                self.sightings.text = String(activityData[0].sightingCount)
                print("SightingsCount: \(activityData[0].sightingCount)")
                self.kills.text = String(activityData[0].killCount)
                self.sightings.text = String(activityData[0].sightingCount)

                if activityData[0].defaultImageURL.isEmpty == false {
                    self.activityImageView.kf.setImage(with: URL.init(string:activityData[0].defaultImageURL))
                }
            }
        }
    }

    // ----------------------------
    // IBActions
    // ----------------------------
    @IBAction func backBtnWasPressed(_ sender: Any) {
        // Navigates back to feedVC
        self.dismiss(animated: true, completion: nil)
    }
}

This is the DataService function that it runs (note I've slimmed down the function so not all variables are there)

// Get data on specific activity
    func getActivityData(activityId: String, handler: @escaping (_ activities: [Activity]) -> ()) {

        var activityData = [Activity]()

        REF_ACTIVITY.child(activityId).observeSingleEvent(of: .value) { (snapshot) in
            guard let activity = snapshot.value as? NSDictionary else { return }

            let activityId =            activityId
            let name =                  activity["name"] as? String ?? ""
            let description =           activity["description"] as? String ?? ""

            let userId =                activity["userId"] as? String ?? ""

            let tempKillCount =         activity["killCount"] as? NSNumber ?? 0
            let killCount =             Int(tempKillCount)

            let tempSightingCount =     activity["sightingCount"] as? NSNumber ?? 0
            let sightingCount =         Int(tempSightingCount)


            let data = Activity(activityId: activityId, name: name, userId: userId, killCount: killCount, sightingCount: sightingCount)
                activityData.append(data)
                print("Within function - print activityData: ")
                dump(activityData)
            }
            handler(activityData)
    }

Upvotes: 1

Views: 809

Answers (2)

Ali Faris
Ali Faris

Reputation: 18630

you need to move the call to your closure (handler) in side the observe listener

observeSingleEvent is async which means it will return immediately then this line will executed handler(activityData) and at that moment activityData is empty

func getActivityData(activityId: String, handler: (activities: [Activity]) -> Void ) 
{

    var activityData = [Activity]()

    REF_ACTIVITY.child(activityId).observeSingleEvent(of: .value) 
    { 
        (snapshot) in

        guard let activity = snapshot.value as? NSDictionary else { return }

        let activityId =            activityId
        let name =                  activity["name"] as? String ?? ""
        let description =           activity["description"] as? String ?? ""
        let userId =                activity["userId"] as? String ?? ""
        let tempKillCount =         activity["killCount"] as? NSNumber ?? 0
        let killCount =             Int(tempKillCount)
        let tempSightingCount =     activity["sightingCount"] as? NSNumber ?? 0
        let sightingCount =         Int(tempSightingCount)


        let data = Activity(activityId: activityId, name: name, userId: userId, killCount: killCount, sightingCount: sightingCount)
        activityData.append(data)
        print("Within function - print activityData: ")
        dump(activityData)

        handler(activityData)

    }   

}

Upvotes: 1

Shehata Gamal
Shehata Gamal

Reputation: 100549

You can achieve this with loading the data and once it's complete push your new VC setted with downloaded data but this is not a good UX one good way to do is Cover the view of the VC with a loading indicator until the request finish and remove the activity indicator and set the data to the labels

Upvotes: 0

Related Questions