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

Code before:
    valueProviders[keypath] = valueProvider
    animationLayer.setValueProvider(valueProvider, keypath: keypath)
  }

  /// Reads the value of a property specified by the Keypath.
  /// Returns nil if no property is found.
  ///
  /// - Parameter for: The keypath used to search for the property.
  /// - Parameter atFrame: The Frame Time of the value to query. If nil then the current frame is used.
  public func getValue(for keypath: AnimationKeypath, atFrame: AnimationFrameTime?) -> Any? {
    animationLayer?.getValue(for: keypath, atFrame: atFrame)
  }

  /// Reads the original value of a property specified by the Keypath.
  /// This will ignore any value providers and can be useful when implementing a value providers that makes change to the original value from the animation.
  /// Returns nil if no property is found.
  ///
  /// - Parameter for: The keypath used to search for the property.
  /// - Parameter atFrame: The Frame Time of the value to query. If nil then the current frame is used.
  public func getOriginalValue(for keypath: AnimationKeypath, atFrame: AnimationFrameTime?) -> Any? {
    animationLayer?.getOriginalValue(for: keypath, atFrame: atFrame)
  }

  /// Gets all child keypaths.
  public func getHierarchyKeypaths() -> [String] {
    animationLayer != nil ? animationLayer!.getHierarchyKeypaths() : []
  }

  /// Logs all child keypaths.
  public func logHierarchyKeypaths() {
    animationLayer?.logHierarchyKeypaths()
  }

  /// Searches for the nearest child layer to the first Keypath and adds the subview
  /// to that layer. The subview will move and animate with the child layer.
  /// Furthermore the subview will be in the child layers coordinate space.
  ///
  /// Note: if no layer is found for the keypath, then nothing happens.
  ///
  /// - Parameter subview: The subview to add to the found animation layer.
  /// - Parameter keypath: The keypath used to find the animation layer.
  ///
  /// Example:
  /// ```
  /// /// A keypath that finds `Layer 1`
  /// let layerKeypath = AnimationKeypath(keypath: "Layer 1")
  ///
  /// /// Wrap the custom view in an `AnimationSubview`
  /// let subview = AnimationSubview()
  /// subview.addSubview(customView)
  ///

Review comment (suggestion):
No need to check for nil / force unwrap:

```suggestion
    animationLayer?.getHierarchyKeypaths() ?? []
```

Code after:
    valueProviders[keypath] = valueProvider
    animationLayer.setValueProvider(valueProvider, keypath: keypath)
  }

  /// Reads the value of a property specified by the Keypath.
  /// Returns nil if no property is found.
  ///
  /// - Parameter for: The keypath used to search for the property.
  /// - Parameter atFrame: The Frame Time of the value to query. If nil then the current frame is used.
  public func getValue(for keypath: AnimationKeypath, atFrame: AnimationFrameTime?) -> Any? {
    animationLayer?.getValue(for: keypath, atFrame: atFrame)
  }

  /// Reads the original value of a property specified by the Keypath.
  /// This will ignore any value providers and can be useful when implementing a value providers that makes change to the original value from the animation.
  /// Returns nil if no property is found.
  ///
  /// - Parameter for: The keypath used to search for the property.
  /// - Parameter atFrame: The Frame Time of the value to query. If nil then the current frame is used.
  public func getOriginalValue(for keypath: AnimationKeypath, atFrame: AnimationFrameTime?) -> Any? {
    animationLayer?.getOriginalValue(for: keypath, atFrame: atFrame)
  }

  /// Logs all child keypaths.
  /// Logs the result of `allHierarchyKeypaths()` to the `LottieLogger`.
  public func logHierarchyKeypaths() {
    animationLayer?.logHierarchyKeypaths()
  }

  /// Computes and returns a list of all child keypaths in the current animation.
  /// The returned list is the same as the log output of `logHierarchyKeypaths()`
  public func allHierarchyKeypaths() -> [String] {
    animationLayer?.allHierarchyKeypaths() ?? []
  }

  /// Searches for the nearest child layer to the first Keypath and adds the subview
  /// to that layer. The subview will move and animate with the child layer.
  /// Furthermore the subview will be in the child layers coordinate space.
  ///
  /// Note: if no layer is found for the keypath, then nothing happens.
  ///
  /// - Parameter subview: The subview to add to the found animation layer.
  /// - Parameter keypath: The keypath used to find the animation layer.
  ///
  /// Example:
  /// ```
  /// /// A keypath that finds `Layer 1`
  /// let layerKeypath = AnimationKeypath(keypath: "Layer 1")
  ///
  /// /// Wrap the custom view in an `AnimationSubview`
  /// let subview = AnimationSubview()