enum LocationError: Error { case unknown } // Async function func getWeatherReadings(for location: String) async throws -> [Double] { switch location { case "London": return (1...100).map { _ in Double.random(in: 6...26) } case "Rome": return (1...100).map { _ in Double.random(in: 10...32) } case "San Francisco": return (1...100).map { _ in Double.random(in: 12...20) } default: throw LocationError.unknown } } // Sync function func fibonacci(of number: Int) -> Int { var first = 0 var second = 1 for _ in 0.. allow us to run concurrent operations either individually // TaskGroup -> or in a coordinated way. /* Task */ /* You can start concurrent work by creating a new Task object and passing it the operation you want to run */ //This will start running on a background thread immediately, //and you can use await to wait for its finished value to come back //Call fibonacci many times on a background thread in order to calculate the first 50 numbers in the sequence: func printFibonacciSequence() async { let task1 = Task { () -> [Int] in //the task starts running as soon as it’s created var numbers = [Int]() for i in 0..<50 { let result = fibonacci(of: i) numbers.append(result) } return numbers } let result1 = await task1.value //the await will wait for the task to finish before continuing print("The first 50 numbers in the Fibonacci sequence are: \(result1)") } //If the code is simpler we do not need to provide the return type. //so this will produce the same result let task1 = Task { (0..<50).map(fibonacci) } // TASK PRIORITY //Priorities: high, default, low, background. let task1 = Task(priority: .high) { (0..<50).map(fibonacci) } //But for the Apple platform the others work too: // userInitiated -> in place of high // utility -> in place of low // userInteractive -> You can't access it because it's for the main thread only // TASK static methds Task.sleep() //sleep for a specific number of nanoseconds (1_000_000_000 -> 1 sec) Task.cancel() //cancel task Task.checkCancellation() //check whether someone has asked for this task to be cancelled and if so throw CancellationError Task.yield() //suspend the current task for a few moments in order to give some time to any tasks that might be waiting //Ex. let task = Task { () -> String in print("Starting") await Task.sleep(1_000_000_000) try Task.checkCancellation() return "Done" } /* TASK GROUP */ /* collections of tasks that work together to produce a finished value. */ // Task groups are created using functions such as withTaskGroup( //Ex. func printMessage() async { let string = await withTaskGroup(of: String.self) { group -> String in //group is the task group group.async { "Hello" } //Add Task to your group (will start immediately) group.async { "From" } //These actually return a single string group.async { "A" } group.async { "Task" } group.async { "Group" } var collected = [String]() for await value in group { collected.append(value) } return collected.joined(separator: " ") } print(string) } //Tip: All tasks in a task group must return the same type of data, //so for complex work you might find yourself needing to return an enum with associated values // If your TASKs throws, use - withThrowingTaskGroup- instead: func printAllWeatherReadings() async { do { print("Calculating average weather…") let result = try await withThrowingTaskGroup(of: [Double].self) { group -> String in group.async { try await getWeatherReadings(for: "London") } group.async { try await getWeatherReadings(for: "Rome") } group.async { try await getWeatherReadings(for: "San Francisco") } // Convert our array of arrays into a single array of doubles let allValues = try await group.reduce([], +) // Calculate the mean average of all our doubles let average = allValues.reduce(0, +) / Double(allValues.count) return "Overall average temperature is \(average)" } print("Done! \(result)") } catch { print("Error calculating data.") } } cancelAll() //method in the taskgroup to cancel them all asyncUnlessCancelled() // taskgroup method to skip adding work if the task has been cancelled