-1

Got A Problem With Swift Function

I wrote a function, and I called it within .onAppear {}. But it returned a value before executing the main body of the function. I'm new to Swift, and I cannot finger it out.

Here is the function definition:

func getUnapprovedCourses(account: String) -> [Course] {
        
        print("===== [1] Main body of the function ===== \n")
        
        let db = Firestore.firestore()
        var coursesArray: [Course] = []
        
        db.collection("temp_courses").whereField("teach_by", isEqualTo: account)
            .getDocuments() { (querySnapshot, err) in
                for document in querySnapshot!.documents {
                    do {
                        let singleCourse: Course = try document.data(as: Course.self)
                        print("===== [2] Append an element ===== \n")
                        coursesArray.append(singleCourse)
                    } catch {
                        print("Place A error... [ FirestoreManager.swift -> UserManager -> getUnapprovedCourses ]")
                    }
                    // print("\(document.documentID) => \(document.data())")
                }
            }
        
        print("===== [3] Return an array ===== \n")
        return coursesArray
    }

And I called the function in this way

.onAppear {
            getCouresesInfo()
        }

// getCoursesInfo()

func getCoursesInfo() {
    let userManager = UserManager()    
    print("===== [0] Call the function ===== \n")      
    coursesArray = userManager.getUnapprovedCourses(account: account)
}

And here are the results printed in the console:

===== [0] Call the function ===== 

===== [1] Main body of the function ===== 

===== [3] Return an array ===== 

===== [2] Append an element ===== 

It returned first and then appended elements. I hope someone can help me out. :) Thx.

I wish it could append some elements to that array coursesArray, then return the value.

NexusUA
  • 217
  • 1
  • 3
  • 13
Milo Song
  • 1
  • 2
  • 1
    db.collection method works async . you need to add a completion handler or add a new async-await function that has db.collection{...} operations – Omer Tekbiyik May 24 '23 at 07:25

2 Answers2

2

your .....getDocuments() {...} is an asynchronous function. You have to understand how they work. It means you have to wait until the results are available before you can use them.

Currently, your return coursesArray gets executed immediately with an empty array.

Use a completion handler, as shown in the example code.

 // --- here
 func getUnapprovedCourses(account: String, completion: @escaping([Course]) -> Void) {
     print("===== [1] Main body of the function ===== \n")
     
     let db = Firestore.firestore()
     var coursesArray: [Course] = []
     
     db.collection("temp_courses").whereField("teach_by", isEqualTo: account)
         .getDocuments() { (querySnapshot, err) in
             for document in querySnapshot!.documents {
                 do {
                     let singleCourse: Course = try document.data(as: Course.self)
                     print("===== [2] Append an element ===== \n")
                     coursesArray.append(singleCourse)
                 } catch {
                     print("Place A error... [ FirestoreManager.swift -> UserManager -> getUnapprovedCourses ]")
                 }
                 // print("\(document.documentID) => \(document.data())")
             }
             completion(coursesArray)  // <-- here, inside the async function
         }
 }
 

and use it like this:

 func getCoursesInfo() {
     let userManager = UserManager()
     print("===== [0] Call the function ===== \n")
     // --- here
     userManager.getUnapprovedCourses(account: account) { results in
         self.coursesArray = results
     }
 }
 
0
func getUnapprovedCourses(account: String) -> [Course] {
...
   // return coursesArray
   completion(coursesArray)
}

func getCoursesInfo() {
    let userManager = UserManager()
    print("===== [0] Call the function ===== \n")

    userManager.getUnapprovedCourses(account: account) { coursesArray in
        self.coursesArray = coursesArray
    }
}
NexusUA
  • 217
  • 1
  • 3
  • 13
  • Code only answers are discouraged. I would suggest explaining what you are doing and why. FWIW, the `getUnapprovedCourses` appears to be adopting completion handler pattern, but you never gave it a completion closure parameter. – Rob May 24 '23 at 14:46