Skip to main content
ReusableViewProvider manages object pools for reusable views like code blocks and tables, improving performance when rendering large markdown documents with many complex elements.

Class Definition

public final class ReusableViewProvider

Overview

The provider maintains separate pools for different view types (CodeView and TableView) and handles view acquisition, recycling, and ordering. This reduces memory allocation overhead and improves scrolling performance.

Initialization

public init()
Creates a new reusable view provider with empty object pools.

Usage

Basic Usage

let viewProvider = ReusableViewProvider()
let markdownView = MarkdownTextView(viewProvider: viewProvider)
The provider is typically created once and passed to MarkdownTextView during initialization. You can share a single provider across multiple markdown views if needed.

Shared Provider Pattern

class MarkdownRenderer {
    let sharedProvider = ReusableViewProvider()
    
    func createView() -> MarkdownTextView {
        return MarkdownTextView(viewProvider: sharedProvider)
    }
}

Internal Architecture

View Pooling

The provider maintains two internal object pools:
  • Code View Pool: Recycles CodeView instances for syntax-highlighted code blocks
  • Table View Pool: Recycles TableView instances for markdown tables

View Lifecycle

  1. Acquisition: When MarkdownTextView needs a view, it acquires one from the pool
  2. Usage: The view is configured and displayed in the markdown content
  3. Stashing: When content updates, unused views are returned to the pool
  4. Reordering: Views are reordered to match document structure, minimizing visual glitches

Thread Safety

The provider uses internal locking to ensure thread-safe access to view pools.

Performance Benefits

View recycling provides significant performance improvements:
  • Reduces memory allocations for complex views
  • Minimizes view hierarchy changes during updates
  • Improves scrolling performance in long documents
  • Reduces frame drops during content updates

Default Behavior

If you don’t provide a custom ReusableViewProvider, MarkdownTextView creates its own:
let markdownView = MarkdownTextView() // Uses default ReusableViewProvider()
This is suitable for most use cases. Only create a custom provider if you need to share view pools across multiple markdown views.

Recycled View Types

CodeView

Used for rendering fenced code blocks with syntax highlighting:
\`\`\`swift
let message = "Hello, world!"
print(message)
\`\`\`

TableView

Used for rendering markdown tables:
| Header 1 | Header 2 |
|----------|----------|
| Cell 1   | Cell 2   |

Best Practices

Single View

Use the default provider when rendering a single markdown view

Multiple Views

Share a provider across multiple views to maximize pooling efficiency

Memory Management

Providers automatically manage pool sizes - no manual cleanup needed

Thread Safety

Safe to pass the same provider to views on different threads

Example: Multi-Pane Markdown Editor

class MarkdownEditor {
    let viewProvider = ReusableViewProvider()
    
    lazy var previewPane: MarkdownTextView = {
        MarkdownTextView(viewProvider: viewProvider)
    }()
    
    lazy var comparePane: MarkdownTextView = {
        MarkdownTextView(viewProvider: viewProvider)
    }()
    
    func updateContent(_ markdown: String) {
        // Both views share the same view pool
        previewPane.setMarkdown(string: markdown)
        comparePane.setMarkdown(string: markdown)
    }
}

Build docs developers (and LLMs) love