Search code examples
iosswiftasync-awaittaskdo-catch

Why is code execution not leaving Task’s do block? Swift


Update: I've posted an image of the stack trace and the text for the full stack trace (gotten after pausing the program, and typing "bt" into the terminal/debug console) at the bottom of this post. The return print statements at the bottom of this post are also still the same, and correspond to this stack trace info.


This question is related to this question post: How to call an instance of a class that makes an API call, and a function within that class that makes the request, and assign this to variable? Swift, and is a continuation of that project.

I’m trying to make a few API requests for a few date-times (with each API request being for one date-time) then use the resulting values to build a new class whom’s data will be shown in a view.

However, the code execution is not leaving the second date-time’s Task’s do block (this is for the API request for the second date time). I’ve provided print statements that show this, of which are after the code “files” below.

I’m thinking I may need to use a Task block for when setting self.venues = getInitialVenueInfoWithAllOpenAtDateTimeProperties(etc…) in Initial Results View Controller.

I’m using the Yelp Fusion API for this.

Code:

InitialBusinessResultsViewController.swift:

import UIKit
import CoreLocation

class InitialBusinessResultsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    
    @IBOutlet var initialVenueResultsTableView: UITableView!
    
    var venues: [Venue] = []
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        initialVenueResultsTableView.register(UINib(nibName: "CustomTableViewCell", bundle: nil), forCellReuseIdentifier: "CustomTableViewCell")
        initialVenueResultsTableView.delegate = self
        initialVenueResultsTableView.dataSource = self
        
        //Print Check.
        //Prints.
        print("Print Check: Right before self.venues = getInitialVenueInfoWithAllOpenAtDateTimeProperties(etc...).")
        
        
        self.venues = getInitialVenueInfoWithAllOpenAtDateTimeProperties(latitude: latitudeVariableGoesHere, longitude: longitudeVariable, category: "category query goes here", sortBy: "sortBy query goes here", openAtForDateTime1: retrieveDateTimeForDateTime1(), openAtForDateTime2: retrieveDateTimeForDateTime2(), openAtForDateTime3: retrieveDateTimeForDateTime3())
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
           return venues.count
       }
       
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
       let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for: indexPath) as! CustomTableViewCell
       
       //Details for custom table view cell go here.
    }
    //Rest of table view protocol functions.
}

GetInitialVenueInfo.swift:

import Foundation
import CoreLocation

extension InitialBusinessResultsViewController {
    func getInitialVenueInfoWithAllOpenAtDateTimeProperties(latitude: Double,
            longitude: Double,
            category: String,
            sortBy: String,
            openAtForDateTime1: Int?,
            openAtForDateTime2: Int?,
            openAtForDateTime3: Int?,
            openAtForDateTime4: Int?) -> [CompleteInitialVenueInfoWithAllOpenAtDateTimesProperties] {


        //Print check.
        print("Just got into getInitialVenueInfoWithAllOpenAtDateTimeProperties function.")


        //Initiializing API Class.
        let yelpApi = YelpApi(apiKey: "Api key")
        
        //Print check.
        print("Line right before Task { do { self.venuesOpenAtDateTime1 = try await yelpApi.searchBusiness() etc.")

        //Task for DateTime1.
        Task {
            do {
                self.venuesOpenAtDateTime1 = try await yelpApi.searchBusiness(latitude: latitude, longitude: longitude, category: category, sortBy: sortBy, openAt: openAtForDateTime1)
                
                //Print Check.
                print("After 'self.venuesOpenAtDateTime1 = try await yelpApi.searchBusiness(etc....")
                
                //Is comemtned out for now, beacue I likley wont be using this here.
//                self.initialResultsTableView.reloadData()
                
                //Print Check.
                print("After commented out 'self.initialVenueResultsTableView.reloadData()'.")
            } catch {
                    print("Error info for catch block in Task block for DateTime1 in getInitialVenueInfoWithAllDateTimeProperties for making API request: \(error)")
            }
        }

        //Print check.
        print("Line right after Task { do { self.venuesOpenAtDateTime1 = try await yelpApi.searchBusiness() etc., and before the second task (for DateTime2 initial API request).")

        
        //Task for DateTime2.
        Task {
            do {
                self.venuesOpenAtDateTime2 = try await yelpApi.searchBusiness(latitude: latitude, longitude: longitude, category: category, sortBy: sortBy, openAt: openAtForDateTime2)

                //Print Check.
                print("After commented out 'self.venuesOpenAtDateTime2 = try await yelpApi.searchBusiness(etc....")
                
                
                //Is comemtned out for now, beacue I likley wont be using this here.
//                self.initialVenueResultsTableView.reloadData()

                //Print Check.
                print("After commented out 'self.initialVenueResultsTableView.reloadData()’.")
                
            } catch {
                    print("Error info for catch block in Task block in getInitialVenueInfoWithIfOpenAtSatOrSun201AMDateTimes_FriOrSatAFter2AMForUserProperties for making API request: \(error)")
            }
        }

        //Print check.
        print("Line right after Task { do { self.venuesOpenAtDateTime2 = try await yelpApi.searchBusiness() etc.")

        //Print check.
        print("Line right before Task { do { self.venuesOpenAtDateTime3 = try await yelpApi.searchBusiness() etc.")
        
        
        //Task for DateTime3
        Task {
            do {
                self.venuesOpenAtDateTime3 = try await yelpApi.searchBusiness(latitude: latitude, longitude: longitude, category: category, sortBy: sortBy, openAt: openAtForDateTime3)

                //Print Check.
                print("After commented out 'self.venuesOpenAtDateTime3 = try await yelpApi.searchBusiness(etc....")
                
                //Is commented out for now, beacue I likley wont be using this here.
//                self.initialVenueResultsTableView.reloadData()

                //Print Check.
                print("After commented out 'self.initialVenueResultsTableView.reloadData()’.")
            } catch {
                    print("Error info for catch block in Task block in getInitialVenueInfoWithIfOpenAtSatOrSun201AMDateTimes_FriOrSatAFter2AMForUserProperties for making API request: \(error)")
            }
        }

        //Print check.
        print("Line right after Task { do { self.venuesOpenAtDateTime3 = try await yelpApi.searchBusiness() etc.")


        //Print check.
        print("Line right before Task { do { self.venuesOpenAtDateTime4 = try await yelpApi.searchBusiness() etc.")
        
        
        //Task for DateTime4
        Task {
            do {
                self.venuesOpenAtDateTime4 = try await yelpApi.searchBusiness(latitude: latitude, longitude: longitude, category: category, sortBy: sortBy, openAt: openAtForDateTime4)

                //Print Check.
                print("After commented out 'self.venuesOpenAtDateTime4 = try await yelpApi.searchBusiness(etc....")
                
                
                //Is comemtned out for now, beacue I likley wont be using this here.
//                self.initialVenueResultsTableView.reloadData()

                //Print Check.
                print("After commented out 'self.initialVenueResultsTableView.reloadData()’.")
            } catch {
                    print("Error info for catch block in Task block in getInitialVenueInfoWithAllOpenAtDateTimesProperties for making API request: \(error)")
            }
        }

        //Print check.
        print("Line right after Task { do { self.venuesOpenAtDateTime4 = try await yelpApi.searchBusiness() etc.")

        //Print check.
        print("Line right before 'let completeVenuesListWithAllOpenAtDateTimeProperties = createCompleteVenuesListWithAllOpenAtDateTimesProperties()'.")



        //Next Phase of this function.
        let completeVenuesListWithAllOpenAtDateTimeProperties = createCompleteVenuesListWithAllOpenAtDateTimesProperties(venuesThatAreOpenAtDateTime1: venuesOpenAtDateTime1, venuesThatAreOpenAtDateTime2: venuesOpenAtDateTime2,
            venuesThatAreOpenAtDateTime3: venuesOpenAtDateTime3,
            venuesThatAreOpenAtDateTime4: venuesOpenAtDateTime4)

        //Print check.
        print("Line right after 'let completeVenuesListWithAllOpenAtDateTimeProperties = createCompleteVenuesListWithAllOpenAtDateTimesProperties()', and before 'return completeVenuesListWithAllOpenAtDateTimeProperties'.")

        return completeVenuesListWithAllOpenAtDateTimeProperties

    }
}

CreateCompleteVenuesInfoList.swift:

import Foundation
import CoreLocation


func createCompleteVenuesListWithAllOpenAtDateTimesProperties(venuesThatAreOpenAtDateTime1: [InitiallyDisplayedVenueInfo],
   venuesThatAreOpenAtDateTime2: [InitiallyDisplayedVenueInfo],
   venuesThatAreOpenAtDateTime3: [InitiallyDisplayedVenueInfo],
   venuesThatAreOpenAtDateTime4: [InitiallyDisplayedVenueInfo]) -> [CompleteInitialVenueInfoWithAllOpenAtDateTimesProperties] {
  
  //Print check.
  print("Just got into func createCompleteVenuesListWithAllOpenAtDateTimesProperties() function.")
  
  
  var completeInitialVenueInfoList: [CompleteInitialVenueInfoWithAllOpenAtDateTimesProperties] = []
  
  
  //Print check.
  print("Right before 'for element in venuesThatAreOpenAtDateTime1 {'.")

  //Adding venuesThatAreOpenAtDateTime1 to completeInitialVenueInfoList.
  for element in venuesThatAreOpenAtDateTime1 {
      let venueOpenAtDateTime1 = CompleteInitialVenueInfoWithAllOpenAtDateTimesProperties(rating: element.rating, price: element.price, phone: element.phone, alias: element.alias, id: element.id, isClosed: element.isClosed, categories: element.categories, review_count: element.review_count, name: element.name, url: element.url, coordinates: element.coordinates, image_url: element.image_url, location: element.location, distance: element.distance, transactions: element.transactions, isOpenAtDateTime1: true, isOpenAtDateTime2: false)
      
      completeInitialVenueInfoList.append(venueOpenAtDateTime1)
  }
  
  //For Checking venues openAtDateTime2 and doing appropriate actions.
  for element in venuesThatAreOpenAtDateTime2 {
      var venueOpenAtDateTime2 = CompleteInitialVenueInfoWithAllOpenAtDateTimesProperties(rating: element.rating, price: element.price, phone: element.phone, alias: element.alias, id: element.id, isClosed: element.isClosed, categories: element.categories, review_count: element.review_count, name: element.name, url: element.url, coordinates: element.coordinates, image_url: element.image_url, location: element.location, distance: element.distance, transactions: element.transactions, isOpenAtDateTime1: false, isOpenAtDateTime2: true)
      
      var countForCurrentVenueIDForDateTime2BeingInVenueAlreadyInCompleteInitialVenueInfoListWhichIsTheCurrentIterationPositionOfCompleteVenueInfoListInBelowForLoop = 0

      for venueAlreadyInCompleteInitialVenueInfoList in completeInitialVenueInfoList {
          if venueAlreadyInCompleteInitialVenueInfoList.id == venueOpenAtDateTime2.id {
              
              print("This venue is already in venuesList, so will make openAtDateTime2 = true")

              countForCurrentVenueIDForDateTime2BeingInVenueAlreadyInCompleteInitialVenueInfoListWhichIsTheCurrentIterationPositionOfCompleteVenueInfoListInBelowForLoop += 1
              
              venueAlreadyInCompleteInitialVenueInfoList.isOpenAtDateTime2 = true
          }
      }
          
      
      print("currentVenueIDForDateTime2BeingInVenueAlreadyInVenuesListInVenuesListInBelowForLoop after for loop and before if statement checking to see if its zero:", countForCurrentVenueIDForDateTime2BeingInVenueAlreadyInCompleteInitialVenueInfoListWhichIsTheCurrentIterationPositionOfCompleteVenueInfoListInBelowForLoop)

      
      if countForCurrentVenueIDForDateTime2BeingInVenueAlreadyInCompleteInitialVenueInfoListWhichIsTheCurrentIterationPositionOfCompleteVenueInfoListInBelowForLoop == 0 {
          
          completeInitialVenueInfoList.append(venueOpenAtDateTime2)
          
      }
  }
      
  //For Checking venues openAtDateTime3 and doing appropriate actions.
  //*Code goes here*
    
  //For Checking venues openAtDateTime4 and doing appropriate actions.
  //*Code goes here*
    
  return completeInitialVenueInfoList
}

Venue.swift:

import Foundation

// MARK: - BusinessSearchResult
struct BusinessSearchResult: Codable {
    let total: Int
    let businesses: [Venue]
    let region: Region
}

// MARK: - Venue
struct Venue: Codable {
    let rating: Double
    let price, phone, alias: String?
    let categories: [Category]
    let coordinates: Center
    let location: LocationOfVenue
    etc.
}

// MARK: - Category
struct Category: Codable {
    let alias, title: String
}

// MARK: - Center
struct Center: Codable {
    let latitude, longitude: Double
}

// MARK: - LocationOfVenue
struct LocationOfVenue: Codable {
    let city, country, address2, address3: String?
    let state, address1, zipCode: String?
}

// MARK: - Region
struct Region: Codable {
    let center: Center
}

FetchData.swift:

import Foundation
import CoreLocation

class YelpApi {
    
    private var apiKey: String
    
    init(apiKey: String) {
        self.apiKey = apiKey
    }
    
    func searchBusiness(latitude: Double,
                        longitude: Double,
                        category: String,
                        sortBy: String) async throws -> [Venue] {
        
        var queryItems = [URLQueryItem]()
        queryItems.append(URLQueryItem(name:"latitude",value:"\(latitude)"))
        queryItems.append(URLQueryItem(name:"longitude",value:"\(longitude)"))
        queryItems.append(URLQueryItem(name:"categories", value:category))
        queryItems.append(URLQueryItem(name:"sort_by",value:sortBy))
       
        var results = [Venue]()
        
        var expectedCount = 0
        let countLimit = 50
        var offset = 0
        
        queryItems.append(URLQueryItem(name:"limit", value:"\(countLimit)"))
        
        //Print Check.
        //Prints.
        print("Print Check: Line before repeat-while loop.")
        
        repeat {
            
            //Print Check.
            //Prints.
            print("Print Check: Within repeat-while loop and before first line of code within it.")
            
            var offsetQueryItems = queryItems
            
            offsetQueryItems.append(URLQueryItem(name:"offset",value: "\(offset)"))
            
            var urlComponents = URLComponents(string: "https://api.yelp.com/v3/businesses/search")
            urlComponents?.queryItems = offsetQueryItems
            
            guard let url = urlComponents?.url else {
                throw URLError(.badURL)
            }
            
            var request = URLRequest(url: url)
            request.setValue("Bearer \(self.apiKey)", forHTTPHeaderField: "Authorization")
            
            //Print Check.
            //Prints.
            print("Print Check: Within repeat-while loop and before 'let (data, _) = try await' line of code.")
            let (data, _) = try await URLSession.shared.data(for: request)
            
            //Print Check.
            //Prints.
            print("Print Check: Within repeat-while loop and before 'let businessResults = try JSONDecoder()' line of code.")
            let businessResults = try JSONDecoder().decode(BusinessSearchResult.self, from:data)
            
            //Print Check.
            //Doesn't print.
            print("Print Check: Within repeat-while loop and right after 'let businessResults = try JSONDecoder()' line of code.")

            expectedCount = min(businessResults.total,1000)
            
            results.append(contentsOf: businessResults.businesses)
            offset += businessResults.businesses.count
        } while (results.count < expectedCount)
        
        //Print Check.
        //Doesn't print.
        print("Print Check: After repeat-while loop and before 'return results' code.")
        
        return results
    }
}

Relevant Return Print Statements From Terminal:

...
Print Check: Within repeat-while loop and before 'let businessResults = try JSONDecoder()' line of code.
Print Check: Within repeat-while loop and right after 'let businessResults = try JSONDecoder()' line of code.
Print Check: After repeat-while loop and before 'return results' code.
After 'self.venuesOpenAtDateTime1 = try await yelpApi.searchBusiness(etc...)'.
After commented out 'self.initialVenueResultsTableView.reloadData()' for Saturday201AMDateTime.
'data' results after 'let (data, _) = try await URLSession.shared.data(for: request)': {"businesses": [{"id": "q8cxhvpTVMR9jDz02bLO0Q", "alias": "mcdonalds-orlando-95", "name": "McDonald's", "image_url": "https://s3-media3.fl.yelpcdn.com/bphoto/DgurmRdXFEzgZ4CgDzXjaw/o.jpg", "is_closed": false, "url": "https://www.yelp.com/biz/mcdonalds-orlando-95?adjust_creative=mgN_4fA5wlIrHQMgamUFAQ&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_search&utm_source=mgN_4fA5wlIrHQMgamUFAQ", "review_count": 22, "categories": [{"alias": "coffee", "title": "Coffee & Tea"}, {"alias": "burgers", "title": "Burgers"}, {"alias": "hotdogs", "title": "Fast Food"}], "rating": 1.5, "coordinates": {"latitude": 28.496012, "longitude": -81.397374}, "transactions": ["delivery"], "price": "$", "location": {"address1": "4640 S Orange Blossom Trl", "address2": null, "address3": null, "city": "Orlando", "zip_code": "32839", "country": "US", "state": "FL", "display_address": ["4640 S Orange Blossom Trl", "Orlando, FL 32839"]}, "phone": "+14078393840", "display_phone": "(407) 839-3840", "distance": 5009.2725621576255}, {"id": "x0FAXbH-WyF98iwdbEYqCA", "alias": "mcdonalds-orlando-58", "name": "McDonald's", "image_url": "https://s3-media3.fl.yelpcdn.com/bphoto/wyyZGkLIh6GbNY4llzRcVQ/o.jpg", "is_closed": false, "url": "https://www.yelp.com/biz/mcdonalds-orlando-58?adjust_creative=mgN_4fA5wlIrHQMgamUFAQ&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_search&utm_source=mgN_4fA5wlIrHQMgamUFAQ", "review_count": 40, "categories": [{"alias": "burgers", "title": "Burgers"}, {"alias": "hotdogs", "title": "Fast Food"}, {"alias": "coffee", "title": "Coffee & Tea"}], "rating": 1.5, "coordinates": {"latitude": 28.5244142835729, "longitude": -81.4706135541201}, "transactions": ["delivery"], "price": "$", "location": {"address1": "1411 S Hiawassee Rd", "address2": "", "address3": "", "city": "Orlando", "zip_code": "32835", "country": "US", "state": "FL", "display_address": ["1411 S Hiawassee Rd", "Orlando, FL 32835"]}, "phone": "+14072989366", "display_phone": "(407) 298-9366", "distance": 9101.306813820358},etc....
Print Check: Within repeat-while loop and before 'let businessResults = try JSONDecoder()' line of code.
Print Check: Within repeat-while loop and right after 'let businessResults = try JSONDecoder()' line of code.
Print Check: After repeat-while loop and before 'return results' code.
After 'self.venuesOpenAtDateTime2 = try await yelpApi.searchBusiness(etc...).
After commented out 'self.initialVenueResultsTableView.reloadData()' for DateTime2.

Screenshot of Stack Trace captured after pausing the program when it was hanging (after the above last print statement):

enter image description here

Full Stack Trace Print Statement from Terminal/Debug Console:

* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  * frame #0: 0x00007fff7016c97a libsystem_kernel.dylib`mach_msg_trap + 10
    frame #1: 0x00007fff7016cce8 libsystem_kernel.dylib`mach_msg + 56
    frame #2: 0x000000010af7eacc CoreFoundation`__CFRunLoopServiceMachPort + 319
    frame #3: 0x000000010af790e2 CoreFoundation`__CFRunLoopRun + 1249
    frame #4: 0x000000010af78704 CoreFoundation`CFRunLoopRunSpecific + 562
    frame #5: 0x000000010dc49c8e GraphicsServices`GSEventRunModal + 139
    frame #6: 0x0000000115f2065a UIKitCore`-[UIApplication _run] + 928
    frame #7: 0x0000000115f252b5 UIKitCore`UIApplicationMain + 101
    frame #8: 0x000000010cb1fcc2 libswiftUIKit.dylib`UIKit.UIApplicationMain(Swift.Int32, Swift.Optional<Swift.UnsafeMutablePointer<Swift.UnsafeMutablePointer<Swift.Int8>>>, Swift.Optional<Swift.String>, Swift.Optional<Swift.String>) -> Swift.Int32 + 98
    frame #9: 0x000000010a5f0c88 Project Name`static UIApplicationDelegate.main() at <compiler-generated>:0
    frame #10: 0x000000010a5f0c17 Project Name`static AppDelegate.$main(self=Project_Name.AppDelegate) at AppDelegate.swift:10:1
    frame #11: 0x000000010a5f0d08 Project Name`main at <compiler-generated>:0
    frame #12: 0x000000010a9e4f21 dyld_sim`start_sim + 10
    frame #13: 0x00000001183fb51e dyld`start + 462

Thanks!


Solution

  • Let us focus on getInitialVenueInfoWithAllOpenAtDateTimeProperties. It can be distilled down to the following:

    func getInitialVenueInfoWithAllOpenAtDateTimeProperties(...) -> [CompleteInitialVenueInfoWithAllOpenAtDateTimesProperties] {
        let yelpApi = YelpApi(apiKey: "Api key")
    
        Task {
            self.venuesOpenAtDateTime1 = try await yelpApi.searchBusiness(latitude: latitude, longitude: longitude, category: category, sortBy: sortBy, openAt: openAtForDateTime1)
        }
    
        Task {
            self.venuesOpenAtDateTime2 = try await yelpApi.searchBusiness(latitude: latitude, longitude: longitude, category: category, sortBy: sortBy, openAt: openAtForDateTime2)
        }
    
        Task {
            self.venuesOpenAtDateTime3 = try await yelpApi.searchBusiness(latitude: latitude, longitude: longitude, category: category, sortBy: sortBy, openAt: openAtForDateTime3)
        }
    
        Task {
            self.venuesOpenAtDateTime4 = try await yelpApi.searchBusiness(latitude: latitude, longitude: longitude, category: category, sortBy: sortBy, openAt: openAtForDateTime4)
        }
    
        // All the above will happen asynchronously, so it will get here before the above finish
    
        return createCompleteVenuesListWithAllOpenAtDateTimesProperties(
            venuesThatAreOpenAtDateTime1: venuesOpenAtDateTime1,
            venuesThatAreOpenAtDateTime2: venuesOpenAtDateTime2,
            venuesThatAreOpenAtDateTime3: venuesOpenAtDateTime3,
            venuesThatAreOpenAtDateTime4: venuesOpenAtDateTime4
        )
    }
    

    That is not going to work. You are launching asynchronous tasks (with Task { ... }), and never await the results.

    You can, for example, make this an async function. For example, if you want these to run concurrently, you can async let each of the results, and try await when you call createCompleteVenuesListWithAllOpenAtDateTimesProperties:

    func getInitialVenueInfoWithAllOpenAtDateTimeProperties(...) async throws -> [CompleteInitialVenueInfoWithAllOpenAtDateTimesProperties] {
        let yelpApi = YelpApi(apiKey: "Api key")
    
        async let venuesOpenAtDateTime1 = yelpApi.searchBusiness(latitude: latitude, longitude: longitude, category: category, sortBy: sortBy, openAt: openAtForDateTime1)
        async let venuesOpenAtDateTime2 = yelpApi.searchBusiness(latitude: latitude, longitude: longitude, category: category, sortBy: sortBy, openAt: openAtForDateTime2)
        async let venuesOpenAtDateTime3 = yelpApi.searchBusiness(latitude: latitude, longitude: longitude, category: category, sortBy: sortBy, openAt: openAtForDateTime3)
        async let venuesOpenAtDateTime4 = yelpApi.searchBusiness(latitude: latitude, longitude: longitude, category: category, sortBy: sortBy, openAt: openAtForDateTime4)
    
        return try await createCompleteVenuesListWithAllOpenAtDateTimesProperties(
            venuesThatAreOpenAtDateTime1: venuesOpenAtDateTime1,
            venuesThatAreOpenAtDateTime2: venuesOpenAtDateTime2,
            venuesThatAreOpenAtDateTime3: venuesOpenAtDateTime3,
            venuesThatAreOpenAtDateTime4: venuesOpenAtDateTime4
        )
    }
    

    Or, if you wanted them to run sequentially, you could simply try await each of the four calls (and remove the try await when you pass it to that aggregating function that you see above):

    func getInitialVenueInfoWithAllOpenAtDateTimeProperties(...) async throws -> [CompleteInitialVenueInfoWithAllOpenAtDateTimesProperties] {
        let yelpApi = YelpApi(apiKey: "Api key")
    
        let venuesOpenAtDateTime1 = try await yelpApi.searchBusiness(latitude: latitude, longitude: longitude, category: category, sortBy: sortBy, openAt: openAtForDateTime1)
        let venuesOpenAtDateTime2 = try await yelpApi.searchBusiness(latitude: latitude, longitude: longitude, category: category, sortBy: sortBy, openAt: openAtForDateTime2)
        let venuesOpenAtDateTime3 = try await yelpApi.searchBusiness(latitude: latitude, longitude: longitude, category: category, sortBy: sortBy, openAt: openAtForDateTime3)
        let venuesOpenAtDateTime4 = try await yelpApi.searchBusiness(latitude: latitude, longitude: longitude, category: category, sortBy: sortBy, openAt: openAtForDateTime4)
    
        return createCompleteVenuesListWithAllOpenAtDateTimesProperties(
            venuesThatAreOpenAtDateTime1: venuesOpenAtDateTime1,
            venuesThatAreOpenAtDateTime2: venuesOpenAtDateTime2,
            venuesThatAreOpenAtDateTime3: venuesOpenAtDateTime3,
            venuesThatAreOpenAtDateTime4: venuesOpenAtDateTime4
        )
    }
    

    There are other permutations on the above, too (e.g., “task groups”), but the key observation is that you really want to avoid unnecessary launching new asynchronous tasks with Task.