Repository: airbnb/lottie-ios
File: Sources/Public/Animation/LottieAnimationHelpers.swift (Swift)

Code before:
  /// - Parameter url: The url to load the animation from.
  /// - Parameter animationCache: A cache for holding loaded animations. Defaults to `LottieAnimationCache.shared`. Optional.
  ///
  public static func loadedFrom(
    url: URL,
    session: URLSession = .shared,
    animationCache: AnimationCacheProvider? = LottieAnimationCache.shared)
    async -> LottieAnimation?
  {
    await withCheckedContinuation { continuation in
      LottieAnimation.loadedFrom(
        url: url,
        session: session,
        closure: { result in
          continuation.resume(returning: result)
        },
        animationCache: animationCache)
    }
  }

  /// Loads a Lottie animation asynchronously from the URL.
  ///
  /// - Parameter url: The url to load the animation from.
  /// - Parameter closure: A closure to be called when the animation has loaded.
  /// - Parameter animationCache: A cache for holding loaded animations. Defaults to `LottieAnimationCache.shared`. Optional.
  ///
  public static func loadedFrom(
    url: URL,
    session: URLSession = .shared,
    closure: @escaping LottieAnimation.DownloadClosure,
    animationCache: AnimationCacheProvider? = LottieAnimationCache.shared)
  {
    if let animationCache, let animation = animationCache.animation(forKey: url.absoluteString) {
      closure(animation)
    } else {
      let task = session.dataTask(with: url) { data, _, error in
        guard error == nil, let jsonData = data else {
          DispatchQueue.main.async {
            closure(nil)
          }
          return
        }
        do {
          let animation = try LottieAnimation.from(data: jsonData)
          DispatchQueue.main.async {
            animationCache?.setAnimation(animation, forKey: url.absoluteString)
            closure(animation)
          }
        } catch {
          DispatchQueue.main.async {
            closure(nil)

Review comment (performance):
```suggestion
    var dataTask: URLSessionDataTask?
    return await withTaskCancellationHandler {
      await withCheckedContinuation { continuation in
        dataTask = LottieAnimation.loadedFrom(
          url: url,
          session: session,
          closure: { result in
            continuation.resume(returning: result)
          },
          animationCache: animationCache)
      }
    } onCancel: {
      dataTask?.cancel()
    }
```

Code after:
  /// - Parameter url: The url to load the animation from.
  /// - Parameter session: The `URLSession` used to load the animation. Defaults to `URLSession.shared`.
  /// - Parameter animationCache: A cache for holding loaded animations. Defaults to `LottieAnimationCache.shared`. Optional.
  ///
  /// - Returns: Loaded Lottie animation, or `nil` if loading failed.
  public static func loadedFrom(
    url: URL,
    session: URLSession = .shared,
    animationCache: AnimationCacheProvider? = LottieAnimationCache.shared)
    async -> LottieAnimation?
  {
    var dataTask: URLSessionDataTask?
    let cancelTask = { dataTask?.cancel() }
    return await withTaskCancellationHandler {
      await withCheckedContinuation { continuation in
        dataTask = LottieAnimation.loadedFrom(
          url: url,
          session: session,
          closure: { result in
            continuation.resume(returning: result)
          },
          animationCache: animationCache)
      }
    } onCancel: {
      cancelTask()
    }
  }

  /// Loads a Lottie 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 closure: A closure to be called when the animation has loaded.
  /// - Parameter animationCache: A cache for holding loaded animations. Defaults to `LottieAnimationCache.shared`. Optional.
  ///
  /// - 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,
    closure: @escaping LottieAnimation.DownloadClosure,
    animationCache: AnimationCacheProvider? = LottieAnimationCache.shared)
    -> URLSessionDataTask?
  {
    if let animationCache, let animation = animationCache.animation(forKey: url.absoluteString) {
      closure(animation)
      return nil
    } else {
      let task = session.dataTask(with: url) { data, _, error in
        guard error == nil, let jsonData = data else {
          DispatchQueue.main.async {