Repository: airbnb/lottie-ios
File: Sources/Private/MainThread/LayerContainers/Utility/CachedImageProvider.swift (Swift)

Code before:
// Created by Jianjun Wu on 2022/5/12.
// Copyright © 2022 Airbnb Inc. All rights reserved.

import CoreGraphics
import Foundation

// MARK: - CachedImageProvider

private final class CachedImageProvider: AnimationImageProvider {

  // MARK: Lifecycle

  /// Initializes an image provider with an image provider
  ///
  /// - Parameter imageProvider: The provider to load image from asset
  ///
  public init(imageProvider: AnimationImageProvider) {
    self.imageProvider = imageProvider
  }

  // MARK: Public

  public func imageForAsset(asset: ImageAsset) -> CGImage? {
    if imageProvider.cacheEligible, let image = imageCache.object(forKey: asset.id as NSString) {
      return image
    }
    if let image = imageProvider.imageForAsset(asset: asset) {
      imageCache.setObject(image, forKey: asset.id as NSString)
      return image
    }
    return nil
  }

  // MARK: Internal

  let imageCache: NSCache<NSString, CGImage> = .init()
  let imageProvider: AnimationImageProvider
}

extension AnimationImageProvider {
  /// Create a cache enabled image provider which will reuse the asset image with the same asset id
  /// It wraps the current provider as image loader, and uses `NSCache` to cache the images for resue.
  /// The cache will be reset when the `animation` is reset.
  var cachedImageProvider: AnimationImageProvider {
    CachedImageProvider(imageProvider: self)
  }
}


Review comment (performance):
Right now this is unnecessarily caching images in the `imageCache` which are never used.

Instead of creating a `CachedImageProvider` but just not reading its cache, perhaps instead we should update the `var cachedImageProvider` implementation below to not create the `CachedImageProvider` at all:

```swift
extension AnimationImageProvider {
  /// Create a cache enabled image provider which will reuse the asset image with the same asset id
  /// It wraps the current provider as image loader, and uses `NSCache` to cache the images for resue.
  /// The cache will be reset when the `animation` is reset.
  /// If this image provider is not eligible for caching, simply returns self.
  var cachedImageProvider: AnimationImageProvider {
    guard cacheEligibile else { return self }
    return CachedImageProvider(imageProvider: self)
  }
}
```

Code after:
// Created by Jianjun Wu on 2022/5/12.
// Copyright © 2022 Airbnb Inc. All rights reserved.

import CoreGraphics
import Foundation

// MARK: - CachedImageProvider

private final class CachedImageProvider: AnimationImageProvider {

  // MARK: Lifecycle

  /// Initializes an image provider with an image provider
  ///
  /// - Parameter imageProvider: The provider to load image from asset
  ///
  public init(imageProvider: AnimationImageProvider) {
    self.imageProvider = imageProvider
  }

  // MARK: Public

  public func imageForAsset(asset: ImageAsset) -> CGImage? {
    if let image = imageCache.object(forKey: asset.id as NSString) {
      return image
    }
    if let image = imageProvider.imageForAsset(asset: asset) {
      imageCache.setObject(image, forKey: asset.id as NSString)
      return image
    }
    return nil
  }

  // MARK: Internal

  let imageCache: NSCache<NSString, CGImage> = .init()
  let imageProvider: AnimationImageProvider
}

extension AnimationImageProvider {
  /// Create a cache enabled image provider which will reuse the asset image with the same asset id
  /// It wraps the current provider as image loader, and uses `NSCache` to cache the images for resue.
  /// The cache will be reset when the `animation` is reset.
  var cachedImageProvider: AnimationImageProvider {
    guard cacheEligible else { return self }
    return CachedImageProvider(imageProvider: self)
  }
}