Repository: airbnb/lottie-ios
File: Sources/Public/DotLottie/DotLottieFileHelpers.swift (Swift)

Code before:
  }

  /// Loads a DotLottie animation asynchronously from the URL.
  ///
  /// - Parameter url: The url to load the animation from.
  /// - Parameter animationCache: A cache for holding loaded animations. Defaults to `LRUAnimationCache.sharedCache`. Optional.
  public static func loadedFrom(
    url: URL,
    session: URLSession = .shared,
    dotLottieCache: DotLottieCacheProvider? = DotLottieCache.sharedCache)
    async throws -> DotLottieFile
  {
    try await withCheckedThrowingContinuation { continuation in
      DotLottieFile.loadedFrom(url: url, session: session, dotLottieCache: dotLottieCache) { result in
        continuation.resume(with: result)
      }
    }
  }

  /// Loads a DotLottie animation asynchronously from the URL.
  ///
  /// - Parameter url: The url to load the animation from.
  /// - Parameter animationCache: A cache for holding loaded animations. Defaults to `LRUAnimationCache.sharedCache`. Optional.
  /// - Parameter handleResult: A closure to be called when the animation has loaded.
  public static func loadedFrom(
    url: URL,
    session: URLSession = .shared,
    dotLottieCache: DotLottieCacheProvider? = DotLottieCache.sharedCache,
    handleResult: @escaping (Result<DotLottieFile, Error>) -> Void)
  {
    if let dotLottieCache, let lottie = dotLottieCache.file(forKey: url.absoluteString) {
      handleResult(.success(lottie))
    } else {
      let task = session.dataTask(with: url) { data, _, error in
        do {
          if let error {
            throw error
          }
          guard let data else {
            throw DotLottieError.noDataLoaded
          }
          let lottie = try DotLottieFile(data: data, filename: url.deletingPathExtension().lastPathComponent)
          DispatchQueue.main.async {
            dotLottieCache?.setFile(lottie, forKey: url.absoluteString)
            handleResult(.success(lottie))
          }
        } catch {
          DispatchQueue.main.async {
            handleResult(.failure(error))
          }
        }

Review comment (performance):
```suggestion
    var dataTask: URLSessionDataTask?
    return try await withTaskCancellationHandler {
      try await withCheckedThrowingContinuation { continuation in
        dataTask = DotLottieFile.loadedFrom(url: url, session: session, dotLottieCache: dotLottieCache) { result in
          continuation.resume(with: result)
        }
      }
    } onCancel: {
      dataTask?.cancel()
    }
```

Code after:
  }

  /// Loads a DotLottie animation asynchronously from the URL.
  ///
  /// - Parameter url: The url to load the animation from.
  /// - Parameter session: The `URLSession` used to load the animation. Defaults to `URLSession.shared`.
  /// - Parameter dotLottieCache: A cache for holding loaded animations. Defaults to `DotLottieCache.sharedCache`. Optional.
  ///
  /// - Returns: Loaded DotLottie animation.
  public static func loadedFrom(
    url: URL,
    session: URLSession = .shared,
    dotLottieCache: DotLottieCacheProvider? = DotLottieCache.sharedCache)
    async throws -> DotLottieFile
  {
    var dataTask: URLSessionDataTask?
    let cancelTask = { dataTask?.cancel() }
    return try await withTaskCancellationHandler {
      try await withCheckedThrowingContinuation { continuation in
        dataTask = DotLottieFile.loadedFrom(url: url, session: session, dotLottieCache: dotLottieCache) { result in
          continuation.resume(with: result)
        }
      }
    } onCancel: {
      cancelTask()
    }
  }

  /// Loads a DotLottie animation asynchronously from the URL.
  ///
  /// - Parameter url: The url to load the animation from.
  /// - Parameter session: The `URLSession` used to load the animation. Defaults to `URLSession.shared`.
  /// - Parameter dotLottieCache: A cache for holding loaded animations. Defaults to `DotLottieCache.sharedCache`. Optional.
  /// - Parameter handleResult: A closure to be called when the animation has loaded.
  ///
  /// - Returns: `URLSessionDataTask` that can be used to cancel the request, or `nil` if the animation was loaded from cache.
  @discardableResult
  public static func loadedFrom(
    url: URL,
    session: URLSession = .shared,
    dotLottieCache: DotLottieCacheProvider? = DotLottieCache.sharedCache,
    handleResult: @escaping (Result<DotLottieFile, Error>) -> Void)
    -> URLSessionDataTask?
  {
    if let dotLottieCache, let lottie = dotLottieCache.file(forKey: url.absoluteString) {
      handleResult(.success(lottie))
      return nil
    } else {
      let task = session.dataTask(with: url) { data, _, error in
        do {
          if let error {