# SKCDataSourcePrefetchingForward in SectionKit: Routing UICollectionView Prefetch Events

> Explore SKCDataSourcePrefetchingForward to route UICollectionView prefetch events to SectionKit sections. Enable efficient async data loading with clean separation.

- Repository: [神奇/sectionkit](https://github.com/linhay/sectionkit)
- Tags: internals
- Published: 2026-03-06

---

**SKCDataSourcePrefetchingForward** is a concrete `UICollectionViewDataSourcePrefetching` implementation that routes iOS prefetch callbacks to SectionKit sections, enabling asynchronous data loading while maintaining clean separation between UIKit and your section logic.

Located in the `linhay/sectionkit` repository, `SKCDataSourcePrefetchingForward` acts as the central router that bridges UIKit's collection view prefetching system with SectionKit's section-based architecture. The class ensures that when a `UICollectionView` requests data ahead of time—such as images or remote JSON—your sections handle the workload without directly conforming to UIKit protocols.

## What is SKCDataSourcePrefetchingForward?

`SKCDataSourcePrefetchingForward` is an **NSObject** subclass residing in [[`SKCDataSourcePrefetchingForward.swift`](https://github.com/linhay/sectionkit/blob/main/SKCDataSourcePrefetchingForward.swift)](https://github.com/linhay/sectionkit/blob/main/Sources/SectionKit/CollectionBaseProtocol/SKCDataSourcePrefetching/SKCDataSourcePrefetchingForward.swift). It conforms to **`UICollectionViewDataSourcePrefetching`** and serves as a multicast router, forwarding prefetch requests to any number of registered handlers and observers.

The class maintains two internal arrays:
- **`forwardItems`**: Objects conforming to `SKCDataSourcePrefetchingForwardProtocol` that handle the actual prefetch work.
- **`observerItems`**: Objects conforming to `SKCDataSourcePrefetchingObserverProtocol` that receive side-effect notifications (e.g., analytics) without blocking the forwarding chain.

## Architectural Role in SectionKit

The prefetching architecture decouples the collection view from section implementations through four distinct layers:

- **Collection View (`UICollectionView`)**: Triggers `prefetchItemsAt` and `cancelPrefetchingForItemsAt` on its `prefetchDataSource`.
- **SKCDataSourcePrefetchingForward**: Receives UIKit callbacks and dispatches them to registered forwards using a chain-of-responsibility pattern.
- **SKCDataSourcePrefetching**: A concrete forward handler (defined in [`SKCViewDataSourcePrefetching.swift`](https://github.com/linhay/sectionkit/blob/main/SKCViewDataSourcePrefetching.swift)) that aggregates index paths by section and invokes `prefetch(at:)` on individual sections.
- **Section (e.g., `SKCSingleTypeSection`)**: Implements `SKCViewDataSourcePrefetchingProtocol` to perform actual data loading or cancellation.

**SKCManager** instantiates and wires these components together during setup, injecting the concrete prefetch handler into the forward.

## How Prefetching Works Under the Hood

### Registration in SKCManager

The wiring occurs inside `SKCManager.setup(sectionView:)`. The manager creates a lazy `SKCDataSourcePrefetchingForward` instance and assigns it as the collection view's `prefetchDataSource`, then registers SectionKit's internal prefetch handler:

```swift
// SKCManager.swift
public private(set) lazy var prefetchForward = SKCDataSourcePrefetchingForward()
public lazy var prefetching = SKCDataSourcePrefetching(dataSource: publishers)

func setup(sectionView: UICollectionView) {
    sectionView.prefetchDataSource = prefetchForward
    prefetchForward.add(prefetching)
}

```

### The Forwarding Chain

When UIKit calls `prefetchItemsAt`, the forward iterates its `forwardItems` **in reverse order**, querying each item via a `find` closure that returns an `SKHandleResult`. The first handler returning `.handle` stops the chain, preventing duplicate work:

```swift
// SKCDataSourcePrefetchingForward.swift
public func collectionView(_ collectionView: UICollectionView,
                           prefetchItemsAt indexPaths: [IndexPath]) {
    let value = find { $0.collectionView(collectionView,
                                        prefetchItemsAt: indexPaths) }
    observe { $0.collectionView(collectionView,
                               prefetchItemsAt: indexPaths, value: value) }
}

```

After the forward completes, all `observerItems` receive the same index paths for logging or metrics.

### Index Path Aggregation

Before reaching individual sections, [[`SKCViewDataSourcePrefetching.swift`](https://github.com/linhay/sectionkit/blob/main/SKCViewDataSourcePrefetching.swift)](https://github.com/linhay/sectionkit/blob/main/Sources/SectionKit/CollectionBaseProtocol/SKCDataSourcePrefetching/SKCViewDataSourcePrefetching.swift) groups index paths by their section component and converts them to row arrays:

```swift
private func prefetch(at indexPaths: [IndexPath]) {
    guard isEnable else { return }
    publishers.prefetchSubject.send(indexPaths)
    var store = [Int: [Int]]()
    for ip in indexPaths {
        store[ip.section, default: []].append(ip.row)
    }
    for (section, rows) in store {
        section(section)?.prefetch(at: rows)
    }
}

```

This ensures that each SectionKit section receives a clean `[Int]` array representing the rows requiring prefetch, rather than raw `IndexPath` objects.

## Implementing Prefetching in Custom Sections

To leverage `SKCDataSourcePrefetchingForward`, your section must implement `SKCViewDataSourcePrefetchingProtocol`. Below is a complete example using `SKCSingleTypeSection`:

```swift
import SectionKit

final class PhotoSection: SKCSingleTypeSection<PhotoModel> {
    
    override init() {
        super.init()
        // Enable the SectionKit prefetch channel
        prefetch.isEnable = true
    }
    
    // Called when cells are about to come on screen
    override func prefetch(at rows: [Int]) {
        let models = rows.map { item(at: $0) }
        ImageCache.prefetch(models.map { $0.imageURL })
    }
    
    // Called when cells scroll away before loading completes
    override func cancelPrefetching(at rows: [Int]) {
        let models = rows.map { item(at: $0) }
        ImageCache.cancelPrefetch(models.map { $0.imageURL })
    }
}

// Usage in a view controller
let collectionView = UICollectionView(frame: view.bounds, 
                                      collectionViewLayout: layout)
let manager = SKCManager(sectionView: collectionView)
let photoSection = PhotoSection()
manager.append(photoSection)
// Prefetching is now automatic as the user scrolls

```

Key implementation details:
- Set **`prefetch.isEnable = true`** in your section's initializer to opt into the forwarding system.
- Override **`prefetch(at:)`** to begin background fetching (images, JSON, etc.).
- Override **`cancelPrefetching(at:)`** to abort expensive operations for cells that scrolled off-screen.

## When to Use SKCDataSourcePrefetchingForward

- **Heavy media assets**: Preload images or videos just before they enter the viewport to eliminate scroll stuttering.
- **Paginated data sources**: Fetch the next page of results while the user is scrolling toward the end of the current list.
- **Network optimization**: Cancel in-flight requests for content that is no longer visible, conserving bandwidth and battery.

## Summary

- **SKCDataSourcePrefetchingForward** is located in [`Sources/SectionKit/CollectionBaseProtocol/SKCDataSourcePrefetching/SKCDataSourcePrefetchingForward.swift`](https://github.com/linhay/sectionkit/blob/main/Sources/SectionKit/CollectionBaseProtocol/SKCDataSourcePrefetching/SKCDataSourcePrefetchingForward.swift) and conforms to `UICollectionViewDataSourcePrefetching`.
- It **decouples** UIKit prefetch callbacks from SectionKit sections by maintaining a list of forward handlers and observers.
- **SKCManager** automatically instantiates the forward and registers the internal `SKCDataSourcePrefetching` handler during setup.
- Sections opt-in by setting `prefetch.isEnable = true` and implementing **`prefetch(at:)`** and **`cancelPrefetching(at:)`** from `SKCViewDataSourcePrefetchingProtocol`.
- The forward uses a **chain-of-responsibility** pattern (reverse iteration) to determine which handler processes the request, then broadcasts to all observers.

## Frequently Asked Questions

### What protocol does SKCDataSourcePrefetchingForward conform to?

`SKCDataSourcePrefetchingForward` conforms to **`UICollectionViewDataSourcePrefetching`**, the UIKit protocol that enables asynchronous data loading for collection views. This allows it to act as the `prefetchDataSource` for any `UICollectionView` instance managed by SectionKit.

### How do I enable prefetching for a specific section?

Set **`prefetch.isEnable = true`** inside your section's initializer. Then implement `prefetch(at:)` and `cancelPrefetching(at:)` methods from `SKCViewDataSourcePrefetchingProtocol` to handle the actual data loading and cancellation logic. Without setting this flag, the forward ignores the section even if the methods are implemented.

### Can I observe prefetch events without handling them?

Yes. Implement **`SKCDataSourcePrefetchingObserverProtocol`** and add your observer to the forward's `observerItems` array. Observers receive notification of all prefetch and cancellation events via the `collectionView(_:prefetchItemsAt:value:)` method, but they cannot block or alter the forwarding chain. This is ideal for analytics, logging, or debugging.

### Where is the prefetch forward instantiated in SectionKit?

The forward is instantiated as a **lazy property** inside `SKCManager`. According to the source in [`SKCManager.swift`](https://github.com/linhay/sectionkit/blob/main/SKCManager.swift), the manager creates `prefetchForward` on first access and wires it to the collection view during `setup(sectionView:)`, assigning it to `sectionView.prefetchDataSource` and registering the internal `SKCDataSourcePrefetching` handler.