# How SKCManager Handles UICollectionView Delegate and DataSource Calls in SectionKit

> Discover how SKCManager delegates UICollectionView calls using a chain-of-responsibility pattern and specialized forward objects. Learn to manage your data efficiently.

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

---

**SKCManager does not implement UICollectionView delegate or dataSource methods directly; instead, it wires specialized forward objects that use a chain-of-responsibility pattern to dispatch calls to registered handlers.**

SKCManager serves as the central orchestrator in SectionKit, a Swift library that simplifies UICollectionView management through a section-based architecture. When initializing an SKCManager instance with a UICollectionView, how SKCManager handles UICollectionView delegate and dataSource calls becomes clear through its unique forwarding mechanism rather than direct protocol implementation.

## The Wiring Architecture in SKCManager

Inside [`Sources/SectionKit/CollectionBase/SKCManager.swift`](https://github.com/linhay/sectionkit/blob/main/Sources/SectionKit/CollectionBase/SKCManager.swift) (lines 30‑38), the `setup(sectionView:)` method replaces the collection view’s delegate and dataSource with specialized forward objects:

```swift
private func setup(sectionView: UICollectionView) {
    self.sectionView = sectionView
    // The collection view’s delegate / data source are replaced
    sectionView.delegate = flowLayoutForward                 // SKCDelegateForward (inherits UICollectionViewDelegate)
    sectionView.dataSource = dataSourceForward               // SKCDataSourceForward (inherits UICollectionViewDataSource)
    sectionView.prefetchDataSource = prefetchForward        // SKCDataSourcePrefetchingForward
    // Register the manager’s own concrete forward objects
    flowLayoutForward.add(delegate)          // SKCDelegate (handles generic delegate callbacks)
    flowLayoutForward.add(flowlayoutDelegate)// SKCDelegateFlowLayout (handles flow‑layout callbacks)
    dataSourceForward.add(dataSource)        // SKCDataSource (handles data‑source callbacks)
    prefetchForward.add(prefetching)        // SKCDataSourcePrefetching
}

```

This architecture ensures that every UICollectionView callback is intercepted by a forward object rather than the manager itself.

## Chain-of-Responsibility Pattern

The forward objects—`SKCDataSourceForward`, `SKCDelegateForward`, and `SKCDelegateFlowLayoutForward`—implement a chain-of-responsibility pattern to determine which handler should process a given call.

### Forward Items vs Observer Items

Each forward object maintains two distinct arrays:

- **`forwardItems`** (or `uiForwards`): Contains objects conforming to `SKCDataSourceForwardableProtocol` or `SKCDelegateForwardProtocol`. These are **potential handlers**—the first item that returns a concrete value (`.handle`) stops the chain.
- **`observerItems`** (or `uiObservers`): Contains objects conforming to `SKCDataSourceObserverProtocol` or `SKCDelegateObserverProtocol`. These are **observers** that receive notification of the final value after the chain resolves.

### The Find Method Implementation

The core dispatch logic resides in [`Sources/SectionKit/CollectionBaseProtocol/SKCDataSource/SKCDataSourceForward.swift`](https://github.com/linhay/sectionkit/blob/main/Sources/SectionKit/CollectionBaseProtocol/SKCDataSource/SKCDataSourceForward.swift) (lines 99‑108). The `find<T>` method iterates through `forwardItems` in reverse order, returning the first concrete result:

```swift
func find<T>(`default`: @autoclosure () -> T,
             _ task: (_ item: SKCDataSourceForwardableProtocol) -> SKHandleResult<T>) -> T {
    for item in forwardItems.reversed() {               // iterate back‑to‑front
        let result = task(item)
        switch result {
        case .handle(let value): return value          // first concrete result wins
        case .next: break
        }
    }
    return `default`()                                 // fallback if none handle
}

```

[`SKCDelegateForward.swift`](https://github.com/linhay/sectionkit/blob/main/SKCDelegateForward.swift) uses an identical pattern for delegate methods such as `shouldSelectItemAt` and `willDisplay`.

## Delegate and DataSource Method Routing

Consider the flow when `collectionView(_:cellForItemAt:)` is invoked:

1. The collection view calls its dataSource’s `cellForItemAt`.
2. Because `sectionView.dataSource` points to `dataSourceForward`, the call lands in `SKCDataSourceForward`.
3. `SKCDataSourceForward` invokes `find`, iterating through `forwardItems` (the manager’s `SKCDataSource` is typically first). If `SKCDataSource` returns `.handle(cell)`, that cell is used; otherwise a default debug cell is returned.
4. After the cell is resolved, `observe` notifies every `observerItem` (e.g., a custom logger) with the final cell value.

All other UICollectionView callbacks follow this identical pattern—they are **routed through the forward objects**, allowing developers to inject custom behaviors without subclassing `UICollectionView`.

## Practical Implementation Examples

### Basic Manager Initialisation

```swift
let layout = UICollectionViewFlowLayout()
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
let manager = SKCManager(sectionView: collectionView)   // delegates & data sources wired automatically

```

### Injecting a Custom Section

```swift
class MySection: SKCSingleTypeSection<String> {
    override func config(sectionView: UICollectionView) {
        // register cell class / nib
        collectionView.register(MyCell.self, forCellWithReuseIdentifier: "MyCell")
    }

    override func cell(collectionView: UICollectionView,
                       indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(
                     withReuseIdentifier: "MyCell", for: indexPath) as! MyCell
        cell.label.text = models[indexPath.item]
        return cell
    }
}

// Add the section to the manager
manager.append(MySection(models: ["A", "B", "C"]))

```

### Adding a Custom Delegate Handler

```swift
struct SizeProvider: SKCDelegateFlowLayoutForwardProtocol {
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAt indexPath: IndexPath) -> SKHandleResult<CGSize> {
        return .handle(CGSize(width: 100, height: 50))
    }
}

// Attach to the flow‑layout forward
manager.flowLayoutForward.add(SizeProvider())

```

## Key Source Files

| File | Role | Link |
|------|------|------|
| [`Sources/SectionKit/CollectionBase/SKCManager.swift`](https://github.com/linhay/sectionkit/blob/main/Sources/SectionKit/CollectionBase/SKCManager.swift) | Central orchestrator; wires delegates/data‑sources. | <https://github.com/linhay/sectionkit/blob/main/Sources/SectionKit/CollectionBase/SKCManager.swift> |
| [`Sources/SectionKit/CollectionBaseProtocol/SKCDataSource/SKCDataSourceForward.swift`](https://github.com/linhay/sectionkit/blob/main/Sources/SectionKit/CollectionBaseProtocol/SKCDataSource/SKCDataSourceForward.swift) | Implements the chain‑of‑responsibility for data‑source methods. | <https://github.com/linhay/sectionkit/blob/main/Sources/SectionKit/CollectionBaseProtocol/SKCDataSource/SKCDataSourceForward.swift> |
| [`Sources/SectionKit/CollectionBaseProtocol/SKCDelegate/SKCDelegateForward.swift`](https://github.com/linhay/sectionkit/blob/main/Sources/SectionKit/CollectionBaseProtocol/SKCDelegate/SKCDelegateForward.swift) | Implements the chain‑of‑responsibility for generic delegate methods. | <https://github.com/linhay/sectionkit/blob/main/Sources/SectionKit/CollectionBaseProtocol/SKCDelegate/SKCDelegateForward.swift> |
| [`Sources/SectionKit/CollectionBaseProtocol/SKCDelegateFlowLayout/SKCDelegateFlowLayoutForward.swift`](https://github.com/linhay/sectionkit/blob/main/Sources/SectionKit/CollectionBaseProtocol/SKCDelegateFlowLayout/SKCDelegateFlowLayoutForward.swift) | Handles flow‑layout specific delegate callbacks. | <https://github.com/linhay/sectionkit/blob/main/Sources/SectionKit/CollectionBaseProtocol/SKCDelegateFlowLayout/SKCDelegateFlowLayoutForward.swift> |

These files together explain how `SKCManager` cleanly abstracts away the raw `UICollectionView` delegate/data‑source plumbing, allowing developers to focus on **section logic** while still being able to inject custom behaviours at any point in the call chain.

## Summary

- **SKCManager** acts as the central coordinator but never implements `UICollectionViewDelegate` or `UICollectionViewDataSource` directly.
- **Forward objects** (`SKCDataSourceForward`, `SKCDelegateForward`, `SKCDelegateFlowLayoutForward`) are wired as the collection view’s official delegate and dataSource.
- **Chain-of-responsibility pattern** allows multiple handlers to attempt processing a call; the first handler returning `.handle(value)` provides the result, while observers receive the final value.
- **Reversed iteration** through `forwardItems` ensures that the most recently added handlers take precedence.
- **Zero subclassing required**—developers inject custom behavior by conforming to forward protocols and adding instances to the manager’s forward objects.

## Frequently Asked Questions

### How does SKCManager differ from traditional UICollectionViewController implementations?

Unlike `UICollectionViewController`, which typically implements delegate and dataSource protocols directly, `SKCManager` delegates all callbacks to specialized forward objects. This decouples the manager from specific UI logic, allowing multiple independent handlers to process collection view events through a chain-of-responsibility pattern.

### What is the difference between forwardItems and observerItems in SKCDataSourceForward?

`forwardItems` contains objects that can **handle** delegate or dataSource calls by returning concrete values via `SKHandleResult.handle(value)`. The chain iterates through these until one returns a handled result. `observerItems` contains objects that **observe** the final outcome after the chain resolves, receiving the value for side effects like logging or analytics but cannot alter the return value.

### Can I use multiple custom handlers for the same delegate method?

Yes. You can add multiple objects conforming to `SKCDelegateForwardProtocol` or `SKCDataSourceForwardableProtocol` to the manager’s forward objects. When a delegate method is called, the chain processes them in reverse order of addition, and the first handler returning `.handle(value)` provides the result. Subsequent handlers in the chain are skipped for that call, but observers still receive the final value.

### Where does the fallback logic execute if no handler processes a call?

If no item in the `forwardItems` array returns `.handle(value)`, the `find` method executes its `@autoclosure` default parameter. For example, in `SKCDataSourceForward`, if no handler provides a cell for `cellForItemAt`, the default closure returns a debug cell or zero count, ensuring the collection view always receives a valid response.