# How to Integrate SectionKit with Combine: Reactive Collection Views in Swift

> Integrate SectionKit with Combine in Swift using subscribe methods and @SKPublished for reactive collection views. Automate data binding and UI updates effortlessly.

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

---

**SectionKit provides native Combine integration through the `subscribe(models:)` method on `SKCSingleTypeSection` and the `@SKPublished` property wrapper, automatically handling data binding, cancellable lifecycle, and main-thread UI updates.**

SectionKit is a Swift framework designed for building modular, section-based `UICollectionView` architectures with minimal boilerplate. When you integrate SectionKit with Combine, you establish a unidirectional data flow where publishers drive UI updates without explicit `reloadData()` calls, as coordinated by `SKCManager`.

## Subscribing Sections to Combine Publishers

The primary integration point lives in `Sources/SectionKit/CollectionSingleTypeSection/Entities/SKCSingleTypeSection+subscribe.swift`. The `subscribe(models:)` method accepts any `Combine` publisher emitting an array of models—or a single model—and binds it to the section's internal state.

### Automatic Thread Safety and Cancellable Management

This method stores the resulting `AnyCancellable` internally within the section’s `publishers` container, eliminating the need for you to maintain separate references. It automatically forces the stream onto the main run loop using `receive(on: RunLoop.main)` before applying data changes.

```swift
import Combine
import SectionKit

class ViewController: SKCollectionViewController {
    private var modelsSubject = CurrentValueSubject<[MyCell.Model], Never>([])
    private lazy var section = MyCell.wrapperToSingleTypeSection()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Subscribe and chain fluently
        section.subscribe(models: modelsSubject)
        manager.reload(section)
    }
}

```

## Reactive State Management with @SKPublished

For fine-grained reactive state outside of array-based sections, the framework provides `@SKPublished`, defined in [`Sources/SectionKit/Common/SKPublished.swift`](https://github.com/linhay/sectionkit/blob/main/Sources/SectionKit/Common/SKPublished.swift). This property wrapper encapsulates values in a `CurrentValueSubject` or `PassthroughSubject`, emitting Combine events whenever the wrapped value changes.

```swift
import Combine
import SectionKit

final class CounterViewModel {
    @SKPublished var count: Int = 0
    
    var countPublisher: AnyPublisher<Int, Never> {
        $count.publisher
    }
    
    func increment() {
        count += 1  // Automatically emits to subscribers
    }
}

// Inside a cell
func config(_ model: Model, viewModel: CounterViewModel) {
    cancellable = viewModel.$count.bind { [weak self] newCount in
        self?.button.setTitle("\(newCount)", for: .normal)
    }
}

```

The `SKPublishedTransform` type provides static helpers such as `removeDuplicates()` and `receiveOnMainQueue()` for composing publisher chains before they reach the section.

## Manager Coordination and Update Propagation

`SKCManager`, implemented in [`Sources/SectionKit/CollectionBase/SKCManager.swift`](https://github.com/linhay/sectionkit/blob/main/Sources/SectionKit/CollectionBase/SKCManager.swift), acts as the central mediator between sections and the collection view. When a publisher emits new data, the section calls `apply(models)` internally; the manager receives this change through the injected `SKCSectionInjection` and triggers the appropriate animations (insertions, deletions, or reloads).

As described in [`Sources/SectionKit/AGENTS.md`](https://github.com/linhay/sectionkit/blob/main/Sources/SectionKit/AGENTS.md), this architecture ensures that all UI updates occur on the main thread while allowing you to emit values from background queues.

## Complete Working Example

The repository includes a concrete demonstration in [`Example/Data/SubscribeDataWithCombineViewController.swift`](https://github.com/linhay/sectionkit/blob/main/Example/Data/SubscribeDataWithCombineViewController.swift), showing a `CurrentValueSubject<[TextCell.Model], Never>` feeding a single-type section. Adding items to the subject instantly updates the collection view without manual intervention.

```swift
import UIKit
import Combine
import SectionKit

class SubscribeDataWithCombineViewController: SKCollectionViewController {
    private let subject = CurrentValueSubject<[TextCell.Model], Never>([])
    private lazy var textSection = TextCell.wrapperToSingleTypeSection()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Bind publisher to section—cancellable stored automatically
        textSection.subscribe(models: subject)
        manager.reload(textSection)
        
        // Simulate async data loading
        DispatchQueue.global().async { [weak self] in
            let newData = (0..<5).map { TextCell.Model(text: "Row \($0)") }
            self?.subject.send(newData)
        }
    }
}

```

This pattern works with any upstream publisher, including those transformed with `filter`, `map`, or `removeDuplicates` operators.

## Summary

- **`subscribe(models:)`**: Binds any Combine publisher to `SKCSingleTypeSection`, storing cancellables internally and enforcing main-thread delivery via `Sources/SectionKit/CollectionSingleTypeSection/Entities/SKCSingleTypeSection+subscribe.swift`.
- **`@SKPublished`**: Provides a general-purpose property wrapper in [`Sources/SectionKit/Common/SKPublished.swift`](https://github.com/linhay/sectionkit/blob/main/Sources/SectionKit/Common/SKPublished.swift) for reactive state that bridges SwiftUI-style observation into UIKit collection views.
- **`SKCManager`**: Mediates between section updates and collection view animations according to [`Sources/SectionKit/AGENTS.md`](https://github.com/linhay/sectionkit/blob/main/Sources/SectionKit/AGENTS.md), requiring no manual `performBatchUpdates` calls when publishers emit.
- **Thread Safety**: All data emissions are automatically scheduled on the main run loop inside the subscription, preventing UI consistency errors regardless of the upstream queue.

## Frequently Asked Questions

### Does SectionKit require manual sink management for Combine subscriptions?

No. When you call `subscribe(models:)` on `SKCSingleTypeSection`, the framework stores the resulting `AnyCancellable` in the section's internal `publishers` set. The subscription lifecycle matches the section's lifecycle, eliminating retain cycles and the need to maintain separate `Set<AnyCancellable>` properties in your view controller.

### How does SectionKit handle threading when using Combine publishers?

The implementation in `SKCSingleTypeSection+subscribe.swift` applies `receive(on: RunLoop.main)` to the publisher chain before updating the model array. This ensures that `SKCManager` always receives data changes on the main thread, preventing the crashes and inconsistencies that occur when updating `UICollectionView` from background queues.

### Can @SKPublished be used outside of collection view cells?

Yes. `@SKPublished` is a general-purpose property wrapper defined in [`Sources/SectionKit/Common/SKPublished.swift`](https://github.com/linhay/sectionkit/blob/main/Sources/SectionKit/Common/SKPublished.swift) that functions in any view model, controller, or service layer. It wraps values in `CurrentValueSubject` or `PassthroughSubject` and supports composition with `SKPublishedTransform` helpers for debouncing, deduplication, or queue-shifting.

### What publisher types are compatible with subscribe(models:)?

Any `Combine` publisher that outputs an array of models conforming to the section's expected type—or a single model when using single-item variants—and never fails (where `Failure == Never`) works with `subscribe(models:)`. Common implementations include `CurrentValueSubject`, `PassthroughSubject`, `@Published` projections, and transformed publishers using `map` or `compactMap` operators.