-1

I brought the substituted sequence out in the closure, but what should I do? "startTimeArrForStart", "endTimeArrForStart", "scheduleArrForStart" will become empty when "return" the contents.

func getScheduleDate(date: Any) -> ([Any], [Any], [Any]) {

    var startTimeArrForStart = [Any]()
    var endTimeArrForStart = [Any]()
    var scheduleArrForStart = [Any]()

    self.db.collection("users").document(fireAuthUID).addSnapshotListener { (snapshot, error) in
        guard let document = snapshot else {
            print("erorr2 \(String(describing: error))")
            return
        }
        guard let data = document.data() else { return }
        self.teamIDFromFirebase = data["teamID"] as? String ?? ""
        self.db
            .collection("teams")
            .document(self.teamIDFromFirebase)
            .collection("schedule")
            .whereField("date_start", isEqualTo: date)
            .getDocuments() { (querySnapshot, err) in
            if err != nil {
                print("scheduleを取得できませんでした")
                return
            } else {
                for document in querySnapshot!.documents {
                    guard let dataFromFirebase: [String : Any] = document.data() else { return }
                    let startTimeFromFirebase = dataFromFirebase["date_start"] ?? ""
                    let endTimeFromFirebase = dataFromFirebase["date_end"] ?? ""
                    let scheduleFromFirebase = dataFromFirebase["event_title"] ?? ""
                    startTimeArrForStart.append(startTimeFromFirebase)
                    endTimeArrForStart.append(endTimeFromFirebase)
                    scheduleArrForStart.append(scheduleFromFirebase)
                    self.tableView.reloadData()
                }
            }
        }
    }
    print(startTimeArrForStart) //<- empty
    print(endTimeArrForStart) //<- empty
    print(scheduleArrForStart) //<- empty
    return (startTimeArrF`enter code here`orStart, endTimeArrForStart, scheduleArrForStart)
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
  • 1
    For simplicity, I'd suggest to write the *minimal* code to show what are you asking about... – Ahmad F Oct 25 '18 at 07:53
  • The concept you are missing is "Asynchronous". If you check correctly, you'll see that `print("scheduleを取得できませんでした")` is printed AFTER `print(startTimeArrForStart)`. – Larme Oct 25 '18 at 08:21
  • You are fighting the strong type system. Don't do that ! All three arrays have distinct types, not `Any`. And why do you use multiple arrays at all. That's another bad habit. – vadian Oct 25 '18 at 08:25

2 Answers2

0

You need to understand how closure work.

self.db.collection("users").document(fireAuthUID).addSnapshotListener { 
    // this section is 'separate' from the code around
    // usually these callbacks (addSnapshotListener) get to be called later on        
}

Here is an approach that may help you

func doSomethingAfterGettingInfoFor(date: Any) { // rename to understand better func getScheduleDate(date: Any) {
        self.db.collection("users").document(fireAuthUID).addSnapshotListener { [weak self] (snapshot, error) in // <- do not create leaks
        self.doSomethingLaterOnWith(snapshot, and: error, calledFor: date)
    }
}

So if previously you were doing something along this line:

func someImplementation() {
    var previousExpectedResults = getScheduleDate(Date())
    // and here you were doing something depending on the result
    print(previousExpectedResults.0)
    print(previousExpectedResults.1)       
}

Now you would do somehting like:

 func someImplementation() {
        doSomethingAfterGettingInfoFor(date: Date())   // << -- see from above 
    }

    func doSomethingLaterOnWith(snapshot: SnapshotType, and error: ErrorType, calledFor: Date) {
        // and here you were doing something depending on the result


         guard let document = snapshot else {
                print("erorr2 \(String(describing: error))")
                return
            }
            guard let data = document.data() else { return }
            self.teamIDFromFirebase = data["teamID"] as? String ?? ""
            self.db
                .collection("teams")
                .document(self.teamIDFromFirebase)
                .collection("schedule")
                .whereField("date_start", isEqualTo: date)
                .getDocuments() { (querySnapshot, err) in
                if err != nil {
                    print("scheduleを取得できませんでした")
                    return
                } else {
                    for document in querySnapshot!.documents {
                        guard let dataFromFirebase: [String : Any] = document.data() else { return }
                        let startTimeFromFirebase = dataFromFirebase["date_start"] ?? ""
                        let endTimeFromFirebase = dataFromFirebase["date_end"] ?? ""
                        let scheduleFromFirebase = dataFromFirebase["event_title"] ?? ""
                        startTimeArrForStart.append(startTimeFromFirebase)
                        endTimeArrForStart.append(endTimeFromFirebase)
                        scheduleArrForStart.append(scheduleFromFirebase)
                        self.tableView.reloadData()
                    }
                }
            }


        print(previousExpectedResults.0)
        print(previousExpectedResults.1)       
    }
Durdu
  • 4,649
  • 2
  • 27
  • 47
  • I can not understand it much. What is self.doSomethingLaterOnWith (snapshot, and: error, calledFor: date)? – 小村祐輝 Oct 25 '18 at 08:21
  • You need to implement this method in your class and handle the response from your db. – Durdu Oct 25 '18 at 08:26
  • I will update the example to help you understand. :) – Durdu Oct 25 '18 at 08:30
  • updated, I hope you have a better understanding of it (but I am not sure if the 2nd part of the response works, it is just to help you understand what you need to change – Durdu Oct 25 '18 at 08:43
-1

Closures won't be able to promise updation of captured variables before the execution of your print statement, or the return statement in your function.

Since the 3 arrays are mutated only inside the addSnapshotListener closure, you would not have the updated values when you return, since, the closure is yet to update the values when your code reaches the return statement.

For you to get the updated values for these arrays, you would have to depend on closures to send back the values to the caller of the function.

func getScheduleDate(date: Any, completion: (([Any], [Any], [Any]) -> Void)) ->  {

    var startTimeArrForStart = [Any]()
    var endTimeArrForStart = [Any]()
    var scheduleArrForStart = [Any]()

    self.db.collection("users").document(fireAuthUID).addSnapshotListener { (snapshot, error) in
        guard let document = snapshot else {
            print("erorr2 \(String(describing: error))")

            completion(startTimeArrForStart, endTimeArrForStart, scheduleArrForStart)
            return
        }
        guard let data = document.data() else {
            completion(startTimeArrForStart, endTimeArrForStart, scheduleArrForStart)
            return
        }
        self.teamIDFromFirebase = data["teamID"] as? String ?? ""
        self.db
            .collection("teams")
            .document(self.teamIDFromFirebase)
            .collection("schedule")
            .whereField("date_start", isEqualTo: date)
            .getDocuments() { (querySnapshot, err) in
                if err != nil {
                    print("scheduleを取得できませんでした")
                    completion(startTimeArrForStart, endTimeArrForStart, scheduleArrForStart)
                    return
                } else {
                    for document in querySnapshot!.documents {
                        guard let dataFromFirebase: [String : Any] = document.data() else { return }
                        let startTimeFromFirebase = dataFromFirebase["date_start"] ?? ""
                        let endTimeFromFirebase = dataFromFirebase["date_end"] ?? ""
                        let scheduleFromFirebase = dataFromFirebase["event_title"] ?? ""
                        startTimeArrForStart.append(startTimeFromFirebase)
                        endTimeArrForStart.append(endTimeFromFirebase)
                        scheduleArrForStart.append(scheduleFromFirebase)
                        self.tableView.reloadData()
                    }
                    completion(startTimeArrForStart, endTimeArrForStart, scheduleArrForStart)
                }
        }
    }
}

Fetch the value from the updated function using:

getScheduleDate(date: Date()) { (startTime, endTime, scheduledList) in

    // Update your UI or do any actions based on the fetched data here.
}
D V
  • 348
  • 2
  • 10