Используя Firestore DB, как я могу выйти из значения l oop внутри прослушивателя моментальных снимков при выполнении определенного условия? - PullRequest
0 голосов
/ 08 апреля 2020

Я пытаюсь выйти из этого слушателя, как только это условие if myDay == self.daysOfWeek[self.picker.selectedRow(inComponent: 0)] выполнено, но я не получаю результаты, которые я ищу.

Как только условие выполнено, оно просто продолжает изучать все документы. Как мне правильно написать код?

let addAction = UIAlertAction(title: "Add Workout", style: .default) { (UIAlertAction) in

    if self.dayCount != 0 {
        print("\(self.dayCount)")

        self.colRef.addSnapshotListener { (querySnapshot, err) in

            if let err = err
            {
                print("Error getting documents: \(err)");
            }
            else
            {
                for document in querySnapshot!.documents {
                    let myData = document.data()
                    let myDay = myData["dow"] as? String ?? ""

                    print(self.daysOfWeek[self.picker.selectedRow(inComponent: 0)])
                    print(myDay)
                    if myDay == self.daysOfWeek[self.picker.selectedRow(inComponent: 0)] {
                        containsDay = true
                        print(containsDay)
                        dayId = document.documentID
                        workoutColRef = Firestore.firestore().collection("/users/\(self.userIdRef)/Days/\(dayId)/Workouts/")

                        break //This Break needs to be somewhere else???
                    }
                }
            }
        }

        if containsDay == true {
            //Create new workout and store within the selectedDay.

            workoutColRef.addDocument(data: ["workout" : "\(self.textField2.text!)", "dayRef" : "\(dayId)"])

            self.loadDays()

        } else {
            //Create new day as well as a new workout, and store the workout within the day.

            let newDayRef = self.colRef.addDocument(data: ["dow" : "\(self.daysOfWeek[self.picker.selectedRow(inComponent: 0)])"])

            Firestore.firestore().collection("/users/\(self.userIdRef)/Days/\(newDayRef.documentID)/Workouts/").addDocument(data: ["workout" : "\(self.textField2.text!)", "dayRef" : newDayRef])

            newDayRef.getDocument { (docSnapshot, err) in
                if let err = err
                {
                    print("Error getting documents: \(err)");
                }
                else
                {
                    let myData = docSnapshot!.data()
                    let myDay = myData!["dow"] as? String ?? ""
                    self.daysArray.append(myDay)
                }
            }

            self.dayIdArray.append(newDayRef.documentID)

            self.loadDays()

        }
    } else {
        self.dayCount += 1 //If there are no days/workouts, we create new day as well as a new workout, and store the workout within the day.

        let newDayRef = self.colRef.addDocument(data: ["dow" : "\(self.daysOfWeek[self.picker.selectedRow(inComponent: 0)])"])

        Firestore.firestore().collection("/users/\(self.userIdRef)/Days/\(newDayRef.documentID)/Workouts/").addDocument(data: ["workout" : "\(self.textField2.text!)", "dayRef" : newDayRef])


        newDayRef.getDocument { (docSnapshot, err) in
            if let err = err
            {
                print("Error getting documents: \(err)");
            }
            else
            {
                let myData = docSnapshot!.data()
                let myDay = myData!["dow"] as? String ?? ""
                self.daysArray.append(myDay)
            }
        }

        self.dayIdArray.append(newDayRef.documentID)

        self.loadDays()   
    }
}

Ответы [ 2 ]

2 голосов
/ 08 апреля 2020

Первая проблема с кодом в вопросе заключается в том, что Firestore является асинхронным.

Любой код, следующий за закрытием, будет выполнен перед кодом в закрытии. Для извлечения данных с сервера требуется время, и код внутри замыкания запускается после извлечения этих данных.

Так что эту строку

if containsDay == true {

необходимо переместить.

Ответ Фрэнка превосходен, но другое решение - использовать экранирование вместе с перерывом

Предположим, что мы хотим получить uid пользователя - в этом случае мы перебираем узел user, чтобы найти Боба.

users
   uid_0
      name: "Frank"
   uid_1
      name: "Bill"
   uid_2
      name: "Bob"

Вот код, который мы вызываем нашей функцией с

self.lookForBobsUid(completion: { bobsUid in
    print("Bob's uid is: \(bobsUid)")
})

, а затем функция, которая читает все пользователи, перебирает их, а затем, когда мы находим Боба, возвращает Bobs uid и вырваться из l oop.

func lookForBobsUid(completion: @escaping ( (String) -> Void ) ) {
    let usersCollection = self.db.collection("users")
    usersCollection.getDocuments(completion: { snapshot, error in
        if let err = error {
            print(err.localizedDescription)
            return
        }

        guard let documents = snapshot?.documents else { return }

        for doc in documents {
            let uid = doc.documentID
            let name = doc.get("name") as? String ?? "No Name"
            print("checking name: \(name)")
            if name == "Bob" {
                print("  found Bob, leaving loop")
                completion(uid)
                break
            }
        }
    })

    print("note this line will print before any users are iterated over")
}

Обратите внимание, что я добавил строку в конце кода, чтобы продемонстрировать природу асинхронных вызовов.

Все это сказано Вообще говоря, итерации по коллекциям для поиска чего-либо обычно можно избежать.

Похоже, вы ищете все, что разрешает до

self.daysOfWeek[self.picker.selectedRow(inComponent: 0)]

Если это так, было бы целесообразно запрос self.colRef для этого элемента вместо итерации, чтобы найти его; это будет намного быстрее и потребляет меньше ресурсов, а также будет масштабируемым - что если бы было 100 000 узлов для перебора!

2 голосов
/ 08 апреля 2020

Простой способ - сохранить переменную флага, указывающую, нашли ли вы документ:

let foundIt = false
for document in querySnapshot!.documents {
    if !foundIt {
        let myData = document.data()
        let myDay = myData["dow"] as? String ?? ""

        if myDay == self.daysOfWeek[self.picker.selectedRow(inComponent: 0)] {
            containsDay = true
            dayId = document.documentID
            workoutColRef = Firestore.firestore().collection("/users/\(self.userIdRef)/Days/\(dayId)/Workouts/")

            foundIt = true
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...