Rendering Modes
Relevant source files
The following files were used as context for generating this wiki page:
Rendering modes in SwiftDitherKit determine when and how chart rasters are generated during the SwiftUI view lifecycle. Because ordered-dither textures are rendered as pixel-based images rather than vector paths, the library provides specialized scheduling options to balance performance in interactive interfaces against the requirements of offscreen image generation.
The system is governed by the DitherRenderingMode enumeration, which is propagated through the SwiftUI environment to control all charts within a specific view subtree. This allows developers to switch between background processing for live apps and synchronous evaluation for snapshots.
Sources: Sources/SwiftDitherKit/DitherRenderingMode.swift:4-11, Sources/SwiftDitherKit/SwiftDitherKit.docc/GettingStarted.md:57-65
Mode Definitions
SwiftDitherKit defines two primary rendering modes through the DitherRenderingMode enum.
| Mode | Description | Recommended Use Case |
|---|---|---|
asynchronous | Renders behind an actor and reuses frames from a shared cache. This is the default mode. | Interactive apps, scrolling lists, and live interfaces. |
immediate | Renders during view evaluation, blocking the current thread until the raster is available. | ImageRenderer, snapshot testing, and static offscreen images. |
Sources: Sources/SwiftDitherKit/DitherRenderingMode.swift:5-11
Asynchronous Rendering
In the default .asynchronous mode, charts render their dithered frames away from the Main Actor to maintain interface responsiveness. The DitherAsyncRaster view utilizes SwiftUI .task(id:) modifiers to request frames from the DitherRenderCache. If a newer render request is made before the previous one completes, the old task is cancelled to save resources.
Sources: Sources/SwiftDitherKit/DitherRasterView.swift:156-174, Sources/SwiftDitherKit/SwiftDitherKit.docc/SwiftDitherKit.md:15-18
Immediate Rendering
The .immediate mode bypasses the background task system. This is necessary because SwiftUI's offscreen renderers, such as ImageRenderer, do not typically run asynchronous view tasks. By using .immediate, the DitherAsyncRaster calls renderFrame() directly during the body evaluation, ensuring pixels are available for the snapshot.
Sources: Sources/SwiftDitherKit/DitherRenderingMode.swift:9-11, Sources/SwiftDitherKit/DitherRasterView.swift:153-155, Sources/SwiftDitherKit/SwiftDitherKit.docc/GettingStarted.md:57-65
Architectural Logic
The rendering mode affects the internal logic of the DitherAsyncRaster component, which acts as a dispatcher for the rendering work.
The diagram shows how DitherAsyncRaster branches its execution path based on the environment-provided rendering mode.
Sources: Sources/SwiftDitherKit/DitherRasterView.swift:150-175
Environment Integration
The rendering mode is managed via the SwiftUI Environment. Developers can apply the mode to an entire view hierarchy using the .ditherRenderingMode(_:) view modifier.
Implementation Details
- Environment Key:
DitherRenderingModeKeydefines the default as.asynchronous. - View Extension: A public extension on
Viewallows for easy configuration of subtrees.
extension View {
public func ditherRenderingMode(_ mode: DitherRenderingMode) -> some View {
environment(\.ditherRenderingMode, mode)
}
}
Sources: Sources/SwiftDitherKit/DitherRenderingMode.swift:13-34
Impact on Offscreen Snapshots
When generating image assets or documentation snapshots (such as the project's gallery), .immediate mode is critical. Without it, the resulting image would likely contain empty or clear areas where the asynchronous tasks failed to execute.
The sequence diagram illustrates the synchronous flow required for offscreen rendering tools.
Sources: Sources/DitherKitSnapshot/main.swift:18-21, Sources/SwiftDitherKit/SwiftDitherKit.docc/GettingStarted.md:67-74
Summary
Rendering modes provide the necessary flexibility to handle SwiftDitherKit's unique pixel-level rendering requirements. The .asynchronous mode ensures that high-intensity dithering calculations do not block the main thread during user interaction, while the .immediate mode provides a compatibility bridge for static rendering contexts and offscreen snapshot tools.