Best API Design for Modifying Camera Capture Configurations in SwiftUI Package

Hey folks, I am building a packaged called Aperture, aiming to provide photo capture infrastructures for SwiftUI devs.

It would support advanced capture features provided by AVFoundation, like responsive capture, zero shutter lags, etc. Currently capture features are enabled / disabled by view modifiers, one modifier would modify a capture configuration, for example: View.zeroShutterLagEnabled(), however, this kind of configuration modification will NOT cause any View changes, so attaching view modifiers without any view changes may become confusing.

Based on current API design, you modify configuration like this:

MyCameraView()
   .zeroShutterLagEnabled()
   .responsiveCaptureEnabled()
   /* more configuration modifiers */

I can think of some other API designs:

  1. Use a single view modifier for transforming configurations: View.transformCaptureConfiguration
  • If we have two views within the view hierarchy that uses camera view from Aperture, they can share these configuration modifications.
  • However, capture config change may not affect any view stuffs, so I am not sure if this is the best practice
  1. Add a configuration transformation closure to view initializer: CameraView(configuration: { … }) { … }
  • One view, one configuration
  • Well scoped, nothing added to SwiftUI.View
  1. Create a dedicated capture configuration protocol, e.g. CaptureConfigurationModifier, and use View.captureConfigurationModifier(_:) (just like buttonStyle, listStyle, etc.)

Which one, or, which combination do you think is the best for this scenario? I am looking for inspirations! Thanks :)

Two thoughts that come to mind:

  1. How likely is it that someone is going to have more than one camera view on-screen in the hierarchy at once? If that's rare, then the benefit of having modifiers that can affect multiple views in the same sub-hierarchy diminish.
  2. View modifiers are nice, but they can make it hard to tell what your view's configuration options are just from Xcode autocomplete, because those options are spread out over multiple methods. SwiftUI often solves this by prefixing methods with the name of the view the modifier affects (i.e. cameraShutterLagEnabled(_ enabled:))

In your shoes, I'd probably lean towards your View.transformCaptureConfiguration option, since it creates a single discoverable API surface that users can easily compose into their own view modifiers if they need to.

In this case I'd say it is affecting view stuff because it's affecting the behavior of your camera view, which is how plenty of view modifiers work.

1 Like

That make sense

By the way I checked out your codebase — what you've built is super cool! Nice work.

This feels like the kind of configuration that interactionModes serves for a Map in MapKit. Taking inspiration from that, it would be a configuration at initialization.

Running with the one configuration you mentioned, it seems you’re exposing a behavior of a view that is statically configured and wouldn’t change based on the state. Thinking about other behavioral configurations in SwiftUI it seems like ones that may change based on state are modifiers, whereas configurations that are static decisions are done at initialization (like interaction modes on Map or scroll direction on ScrollView).

Providing reasonable defaults would wind up with only 1-2 parameters being used by consumers at initialization which seems approachable

2 Likes

I've moved this to Using Swift with the api-design tag, which seems like a more appropriate category for it than top-level in Related Projects.

A reviewer flagged this thread as off-topic, which caused it to be hidden for a few hours. While questions about using Apple platform frameworks like SwiftUI should generally go to the Apple developer forums, the API design of open-source Swift libraries is on-topic here, even if those libraries are inextricably built on top of Apple's platform frameworks.