lawndogg
lawndogg

Reputation: 127

function called after first function is being ran first in swift

I am creating a friends list on my app, fetchfriends makes a list of users that person is friends with, fetch user then looks at this list and populates a table view with friends information. This seems like it would work fine but for some reason fetch user is being ran before fetch friends can anyone help me with this? This is my code. I even tried a conditional statement which is now commented out and it just never ran the second function that way.

    override func viewDidLoad() {
    super.viewDidLoad()
    ref = FIRDatabase.database().reference()


    friendsTableView.delegate = self
    friendsTableView.dataSource = self

    fetchfriends()

    //if userspresent == true {
    fetchuser()
   // }
    // Do any additional setup after loading the view.
}



    func fetchfriends () {

    ref.child("users").child(userID!).child("friends").observeSingleEvent(of: .value, with: { (snapshot) in
        if let value = snapshot.value as? NSDictionary {

            let userName = value["username"] as? String ?? ""
            let friendid = value["userid"] as? String ?? ""

            self.userIds.append(friendid)
            self.userspresent = true
        print(userName, friendid)
        }
    })
}

   // var index1:Int = 0
    //if userspresent == true {
func fetchuser () {

    //let count = userIds.count
    for index1 in 0...userIds.count-1 {
        ref.child("users").child(userIds[index1]).observeSingleEvent(of: .value, with: { (snapshot) in

        let value = snapshot.value as? NSDictionary
        let user = User()
        let userName = value?["username"] as? String ?? ""
        let email = value?["email"] as? String ?? ""
        let profileImageUrl = value?["profileImage"] as? String ?? ""
        user.userName = userName
        user.email = email
        user.profileImageUrl = profileImageUrl
        print(user)
        self.users.append(user)

        DispatchQueue.main.async {
            self.friendsTableView.reloadData()
        }



        print(user.userName!, user.email!)

       // print(snapshot)
    }, withCancel: nil)
    }
}

Upvotes: 1

Views: 320

Answers (2)

Forest Kunecke
Forest Kunecke

Reputation: 2160

@Taylor M is correct. These are asynchronous network operations, so you can't really say for certain which one will be completed first. However, since fetchuser relies on data produced in fetchfriends (namely, that there will be values in userIds) you can simply add a closure as a parameter to fetchfriends:

func fetchfriends (_ completion: ((Void) -> Void)?) {
    ref.child("users").child(userID!).child("friends").observeSingleEvent(of: .value, with: { (snapshot) in
    if let value = snapshot.value as? NSDictionary {

        let userName = value["username"] as? String ?? ""
        let friendid = value["userid"] as? String ?? ""

        self.userIds.append(friendid)
        self.userspresent = true
        print(userName, friendid)

        // call the closure function upon completion
        completion?()
    }
})

Now, when you call fetchfriends in viewDidLoad simply do:

fetchfriends {
    // this will be called when the friends are successfully fetched
    self.fetchuser()
}

Upvotes: 3

Taylor M
Taylor M

Reputation: 1865

What's happening is asyncronous network calls. You're incorrect in saying that fetch user is being ran before fetch friends if your code is as follows:

override func viewDidLoad() {
    ...
    fetchfriends()

    //if userspresent == true {
    fetchuser()
    // }
}

In your observeSingleEvent call you provide this function a closure to run after firebase observes that event.

So you call fetchfriends (first) which calls an observeSingleEvent. The OS places this network call on a background thread to do its work, and when the network call is finished, your provided closure is executed. Meanwhile, on the main thread, your program keeps running and calls fetchuser (second) which also calls observeSingeEvent and places that call and closure on a different background thread and your program keeps running. Most likely it seems as though the closure written in the fetchuser method is be run first because that network takes less time and is the first one back.

Upvotes: 0

Related Questions