AndrewWicks
AndrewWicks

Reputation: 83

Swift Dispatch Group in function

thank you in advance. I am working with a UITableView and need an array to be created before loading the cells. I am attempting to use DispatchGroup, I was successful in letting the first array be created but a second array which I also need validPhonesNotUsingApp, in the same function is not created.

I am leaving parts of overall file out.

Thank you.

override func viewDidLoad() {
    super.viewDidLoad()
    let group = DispatchGroup()
    setUpElements()
    group.enter()
    checkContacts(group)
    group.notify(queue: .main){
            self.tableView.dataSource = self
            self.tableView.delegate = self
            self.searchBar.delegate = self
            self.tableView.keyboardDismissMode = .onDrag
            print(self.validPhonesNotUsingApp)
            self.tableView.register(TableViewCellForContacts.nib(), forCellReuseIdentifier: TableViewCellForContacts.identifier)
          }
     }


func checkContacts(_ group: DispatchGroup){
    let db = Firestore.firestore()
    db.collection("UserProfile").document(UserDataConst.UserUID).getDocument { (DocumentSnapshot1, Error1) in
        if Error1 != nil{
            print("Error finding if contacts uploaded")
            group.leave()
        }
        else{
            let hasContacts: Bool = DocumentSnapshot1?.get("Contacts Uploaded") as? Bool ?? false
            if hasContacts == true{
                db.collection("UserProfile").document(UserDataConst.UserUID).collection("ContactFriends").getDocuments { (
                    Snapshot2, Error2) in
                    if Error2 != nil{
                        group.leave()
                        return
                    }
                    else{
                        for x in 0..<Snapshot2!.documents.count{
                            group.enter()
                            let validNumber = self.correctPhoneNumber(Snapshot2!.documents[x].documentID, group)
                            if validNumber != nil{
                                self.validPhoneNumbers.append(validNumber!)
                                let first = Snapshot2!.documents[x].get("First Name") as? String ?? "(ø)"
                                self.validPhoneFirstName.append(first)
                                let last = Snapshot2!.documents[x].get("Last Name") as? String ?? "(ø)"
                                self.validPhoneLastName.append(last)
                                
                            }
                            else{
                            group.leave()
                            }
                        }

                        
                        db.collection("AllPhoneNumbers").getDocuments { (Snapshot3, Error3) in
                            if Error3 != nil{
                                group.leave()
                                return
                            }
                            else{
                                print("OK lemme know what sup")
                                let docs = Snapshot3!.documents
                                group.enter()
                                for x1 in 0..<self.validPhoneNumbers.count{
                                    group.enter()
                                    var found = false
                                    for x2 in 0..<docs.count{
                                        group.enter()
                                        if self.validPhoneNumbers[x1] == docs[x2].documentID{
                                            let uid = docs[x2].get("UID") as! String
                                            db.collection("UserProfile").document(UserDataConst.UserUID).collection("Friends").getDocuments { (QuerySnapshot4, Error4) in
                                                if Error4 != nil{
                                                    group.leave()
                                                    return
                                                }
                                                else if QuerySnapshot4!.documents.count != 0{
                                                    var found2 = false
                                                    for x3 in 0..<QuerySnapshot4!.documents.count{
                                                        group.enter()
                                                        if QuerySnapshot4!.documents[x3].documentID == uid{
                                                            found2 = true
                                                            //group.leave()
                                                            break
                                                        }
                                                        else{
                                                        group.leave()
                                                        }
                                                    }
                                         
                                                    if found2 == false{
                                                        self.UIDsUsingApp.append(uid)
                                                    }
                                                }
                                                else{
                                                    self.UIDsUsingApp.append(uid)
                                                }
                                            }
                                            //self.UIDsUsingApp.append(uid)
                                            found = true
                                            //group.leave()
                                            break
                                        }
                                    }
                                    if found == false{
                                        self.validPhonesNotUsingApp.append(self.validPhoneNumbers[x1])
                                        self.validFirstNotUsingApp.append(self.validPhoneFirstName[x1])
                                        self.validLastNotUsingApp.append(self.validPhoneLastName[x1])
                                        group.leave()
                                    }
                                    print("OK now we getting activ")
                                }
                                //print(self.UIDsUsingApp)
                            }
                        }
                        
                    }
                }
            }
            else{
                group.leave()
                return
            }
        }
    }
}

Upvotes: 0

Views: 998

Answers (2)

Rob
Rob

Reputation: 437442

A few observations:

  1. You do not want to entangle the “completion handler” logic of checkContacts with dispatch groups you might be using within the function. If you ever find yourself passing dispatch group objects around, that’s generally a sign that you are unnecessarily entangling methods.

    So, if you need dispatch group within checkContacts, fine, use that, but don’t encumber the caller with that. Just use the completion handler closure pattern.

  2. Make sure that you are not updating your model objects until the asynchronous process is done.

For example:

func checkContacts(completion: @escaping (Result<[Contact], Error>) -> Void) {
    let group = DispatchGroup()
    var contacts: [Contact] = []            // in this method, we will only update this local variable

    ...

    group.notify(queue: .main) {
        if let error = error {
            completion(.failure(error))
        } else {
            completion(.success(contacts))  // and when we’re done, we’ll report the results
        }
    }
}

And you’d call it like

checkContacts { results in
    switch results {
    case .failure(let error): 
        ...

    case .success(let contacts):
        self.contacts = contacts            // only now will we update model properties
        ...                                 // do whatever UI updates you want, e.g.
        self.tableView.reloadData()
}

Upvotes: 1

matt
matt

Reputation: 534966

I am working with a UITableView and need an array to be created before loading the cells. I am attempting to use DispatchGroup

Well, don't. You cannot do anything "before loading the cells". Do not intermingle table handling with dispatch. And don't use a dispatch group in that way.

Everything about the table view must be done immediately and on the main queue. You register directly in viewDidLoad on the main queue. You return a cell immediately in cellForRowAt:. You do not "wait" with a dispatch group or in any other manner.

If you have data to gather for the table in a time-consuming way, fine; do that on a background queue, and update your data model, and then reload the table (on the main queue). So:

  • Initially, if the data is not ready yet, your data source methods find there is no data and they display an empty table.

  • Later, once you gather your data and tell the table view to reload, your data source methods find there is data and they display it.

Upvotes: 2

Related Questions