Apr 26, 2024 iOS

Returning data from async call in Swift function

To return data from an asynchronous call in Swift, you typically use closures, completion handlers, or async/await if you’re using Swift 5.5 or later. Here are examples of each approach:

  1. Using Completion Handler:
func fetchDataFromURL(_ url: URL, completion: @escaping (Result<Data, Error>) -> Void) {
  URLSession.shared.dataTask(with: url) { data, response, error in
    if let error = error {
      completion(.failure(error))
      return
    }
    guard let data = data else {
      completion(.failure(NSError(domain: "No data found", code: -1, userInfo: nil)))
      return
    }
    completion(.success(data))
  }.resume()
}

// Usage
fetchDataFromURL(someURL) { result in
  switch result {
  case .success(let data):
    // Use the data here
  case .failure(let error):
    // Handle errors
  }
}

Explanation:

  • fetchDataFromURL takes a completion handler closure as an argument.
  • Inside the function, a URL session data task is created.
  • The completion closure is called within the data task closure based on the outcome (success with data, error, or no data).
  • The calling code can handle the results (data or error) within the completion handler.
  1. Using Closures:
func fetchDataFromURL(_ url: URL, completion: @escaping (Result<Data, Error>) -> Void) {
 URLSession.shared.dataTask(with: url) { data, response, error in
    if let error = error {
      completion(.failure(error))
      return
    }
    guard let data = data else {
      completion(.failure(NSError(domain: "No data found", code: -1, userInfo: nil)))
      return
    }
    completion(.success(data))
  }.resume()
}

// Usage
fetchData { data, error in
    if let data = data {
        // Handle successful data retrieval
    } else if let error = error {
        // Handle error
    }
}

Explanation:

  • fetchDataFromURL takes a completion handler closure as an argument.
  • Inside the function, a URL session data task is created.
  • The completion closure is called within the data task closure based on the outcome (success with data, error, or no data).
  • The calling code can handle the results (data or error) within the completion handler.
  1. Using Async/Await (Swift 5.5 or later):
func fetchDataFromURL(_ url: URL) async throws -> Data {
  let response = try await URLSession.shared.data(from: url)
  return response.data
}

// Usage
Task {
  do {
    let data = try await fetchDataFromURL(someURL)
    // Use the data here
  } catch {
    // Handle errors
  }
}

Explanation:

  • fetchDataFromURL is declared as an async function, indicating it performs asynchronous work.
  • Inside the function, try await URLSession.shared.data(from: url) makes an asynchronous network call and waits for the response before proceeding.
  • The function throws any errors encountered during the call.
  • The function returns the retrieved data as Data.

Choosing the Right Method:

  • Async/Await is generally preferred for newer Swift versions (5.5 and above) due to its cleaner syntax and easier error handling.
  • Completion Handler might be necessary for compatibility with older Swift versions or when dealing with multiple asynchronous calls within the same function.