Hibernia Hibernia - 2 months ago 14
Swift Question

Trouble understanding array appending

func EmptySearchBarList(){

self.PersonalSearchesList = []

currentUserFirebaseReference.child("rooms").observeSingleEvent(of: .value) { (snapshot: FIRDataSnapshot) in


if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshots {

print("snap")
print(self.PersonalSearchesList.count) // Calling 0 every single time

DataService.ds.REF_INTERESTS.child(interestKey).observeSingleEvent(of: .value, with: { (snapshot: FIRDataSnapshot) in

if snapshot.value != nil {

if let users = (snapshot.value! as? NSDictionary)?["users"] as? Dictionary<String,AnyObject> {

DataService.ds.REF_USERS.child(topUser).child("pictureURL").observeSingleEvent(of: .value, with: { (snapshot: FIRDataSnapshot) in

self.PersonalSearchesList.append(eachSearch)
print("first one")
print(self.PersonalSearchesList.count)
})
}
}
})

}

print("Second one")
print(self.PersonalSearchesList.count)

print("Calling to set my sorted PersonalSearchesList")
self.mySortedList = self.PersonalSearchesList.sorted{ $0.users > $1.users }

}
}
initialLoadOver = true
}


The print logs

What code I'm trying to ultimately run is this :

var mySortedList = [Interest](){
didSet{
print("this was called")
let myCount = mySortedList.count
print(self.PersonalSearchesList.count)
print(myCount)

self.tableView.reloadData()
}
}


The attempt is to load up my PersonalSearchesList array, and once the snap in snapshots is done running, I'm setting MySortedList equal to PersonalSearchesList and reloading the tableview.

What I don't understand is why the prints are coming out like they are. The snap/ 0's are coming from the top of my for snap in snapshots. It seems like it should instead be snap / 1 , snap / 2, snap / 3.

The code to be called when the snaps are done is correct in the timeline, once the snaps have gone through that code runs. What doesn't make sense is why it's not until after that the items are actually being appended to PersonalSearchesList. Becuase of how everything is Im' setting my filtered array to an empty personal searches array and then afterwards I'm filling it up.

Any ideas here?

edit:

var dispatchGroup = DispatchGroup()
dispatchGroup.enter()
dispatchGroup.leave()

dispatchGroup.notify(queue: DispatchQueue.global(), execute: {

})

Answer

DataService.ds.REF_INTERESTS.child(interestKey).observeSingleEvent is running asynchronous so all of those callbacks (where you actually fill you list) will run when they are called from the DataService.

You could use a dispatch group to do what you want. http://commandshift.co.uk/blog/2014/03/19/using-dispatch-groups-to-wait-for-multiple-web-services/

func EmptySearchBarList(){
var dispatchGroup = DispatchGroup()    
self.PersonalSearchesList = []


currentUserFirebaseReference.child("rooms").observeSingleEvent(of: .value) { (snapshot: FIRDataSnapshot) in


    if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] {
        for snap in snapshots {
            dispatchGroup.enter()
            print("snap")
            print(self.PersonalSearchesList.count) // Calling 0 every single time

            DataService.ds.REF_INTERESTS.child(interestKey).observeSingleEvent(of: .value, with: { (snapshot: FIRDataSnapshot) in

                if snapshot.value != nil {

                    if let users = (snapshot.value! as? NSDictionary)?["users"] as? Dictionary<String,AnyObject> {

                        DataService.ds.REF_USERS.child(topUser).child("pictureURL").observeSingleEvent(of: .value, with: { (snapshot: FIRDataSnapshot) in

                            self.PersonalSearchesList.append(eachSearch)
                            print("first one")
                            print(self.PersonalSearchesList.count)
                        })
                    }
                }
                dispatchGroup.leave()
            })

        }

        dispatchGroup.notify(queue: DispatchQueue.global(), execute: {
            print("Second one")
        print(self.PersonalSearchesList.count)

        print("Calling to set my sorted PersonalSearchesList")
        self.mySortedList = self.PersonalSearchesList.sorted{ $0.users > $1.users }
        })


    }
}
initialLoadOver = true
}

I'm not completely sure you can enter and leave the group several times from the same thread so you might have to wrap the code from enter until the end of the callback in another thread and call it async

Comments