What Is the SKConfigurableView Protocol in SectionKit?

The SKConfigurableView protocol is the core architectural contract in SectionKit that enables type-safe data binding and self-sizing for collection view cells by requiring conforming types to implement both model configuration and preferred size calculation methods.

This protocol sits at the heart of the linhay/sectionkit repository, eliminating the need for manual type casting or reflection when building data-driven UICollectionView layouts. By adopting SKConfigurableView, a view declares exactly what data it can display and how much space it requires, allowing SectionKit to automate cell configuration and layout calculations.

Core Requirements of SKConfigurableView

SKConfigurableView is not a standalone definition. According to the source code in Sources/SectionKit/SKConfigurable/SKConfigurableView.swift, it inherits from two specialized protocols that together form a complete binding contract.

Model Binding via SKConfigurableModelProtocol

The first parent protocol, defined in Sources/SectionKit/SKConfigurable/SKConfigurableModelProtocol.swift, requires an associated Model type and a configuration method:

func config(_ model: Model)

This method is where the view receives its data. When SectionKit's section manager calls cellForItem(at:), it automatically invokes this method to bind the section's data model to the cell.

Layout Size Calculation via SKConfigurableLayoutProtocol

The second parent protocol, located in Sources/SectionKit/SKConfigurable/SKConfigurableLayoutProtocol.swift, requires a static sizing method:

static func preferredSize(limit size: CGSize, model: Model?) -> CGSize

The collection view layout engine calls this method to query the cell's ideal dimensions given a width or height constraint. This enables adaptive, content-driven sizing without manual UICollectionViewDelegateFlowLayout implementations.

Default Implementations and Convenience Extensions

The protocol declaration file includes two practical default implementations that reduce boilerplate for common scenarios.

No-op configuration for Void models:

When a view does not require a data model, the protocol provides an empty implementation:

public extension SKConfigurableView where Model == Void {
    func config(_ model: Model) {}
}

RawRepresentable support:

A convenience overload allows configuration using any RawRepresentable type whose raw value matches the view's Model:

public extension SKConfigurableView {
    func config<T: RawRepresentable>(_ model: T) where Model == T.RawValue {
        config(model.rawValue)
    }
}

Both extensions are defined directly in SKConfigurableView.swift, making them immediately available to all conforming types.

How SKConfigurableView Fits Into SectionKit Architecture

The framework uses this protocol to bridge data and layout in a type-safe manner. When you use SKCSingleTypeSection (defined in Sources/SectionKit/CollectionSingleTypeSection/Entities/SKCSingleTypeSection.swift), the generic section stores a Model type and creates cells that conform to SKConfigurableView.

During the collection view's cellForItem(at:) lifecycle, SectionKit automatically calls cell.config(model) to bind the data. Simultaneously, the layout system queries Cell.preferredSize(limit:model:) to compute attributes, enabling self-sizing cells without runtime type checking or manual size caching.

Implementing SKConfigurableView in Practice

Creating a Configurable Collection View Cell

The standard pattern combines SKConfigurableView with SKLoadViewProtocol for views loaded from code or nibs. Here is a complete implementation based on the example in Example/Foundation/StandardCellViewController.swift:

import UIKit
import SectionKit

final class TitleCell: UICollectionViewCell,
                        SKLoadViewProtocol,
                        SKConfigurableView {

    struct Model {
        let title: String
    }

    typealias Model = Model

    private let label = UILabel()

    func loadView() {
        contentView.addSubview(label)
        label.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 12),
            label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -12),
            label.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8),
            label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8)
        ])
    }

    func config(_ model: Model) {
        label.text = model.title
    }

    static func preferredSize(limit size: CGSize, model: Model?) -> CGSize {
        guard let model = model else { return .zero }
        let text = model.title as NSString
        let width = size.width - 24
        let height = text.boundingRect(
            with: CGSize(width: width, height: .greatestFiniteMagnitude),
            options: [.usesLineFragmentOrigin],
            attributes: [.font: UIFont.systemFont(ofSize: 17)],
            context: nil
        ).height + 16
        return CGSize(width: size.width, height: ceil(height))
    }
}

This cell can now be used in any SectionKit section; the framework handles both data binding and layout calculations automatically.

Wrapping Plain UIViews

For decorative views that are not cells, you can conform any UIView to SKConfigurableView and host it using SKWrapperView. This pattern appears in Example/Foundation/WrapperCellViewController.swift:

import UIKit
import SectionKit

final class SimpleColorView: UIView, SKConfigurableView {
    typealias Model = UIColor

    func config(_ model: UIColor) {
        backgroundColor = model
    }

    static func preferredSize(limit size: CGSize, model: UIColor?) -> CGSize {
        let side = min(size.width, 100)
        return CGSize(width: side, height: side)
    }
}

The wrapper cell manages the view lifecycle while SectionKit queries preferredSize(limit:model:) for layout attributes.

Summary

  • SKConfigurableView combines SKConfigurableModelProtocol and SKConfigurableLayoutProtocol into a single contract for data binding and self-sizing.
  • The protocol requires a config(_:) method to receive data and a static preferredSize(limit:model:) method to report dimensions.
  • Default implementations in SKConfigurableView.swift provide no-op configuration for Void models and convenience overloads for RawRepresentable types.
  • SectionKit sections like SKCSingleTypeSection use this protocol to automate cell configuration and layout without reflection or manual delegate methods.
  • Both UICollectionViewCell subclasses and plain UIView instances can adopt the protocol, enabling reusable, type-safe collection view components.

Frequently Asked Questions

What is the difference between SKConfigurableView and SKConfigurableModelProtocol?

SKConfigurableModelProtocol only defines the Model associated type and the config(_:) method for data binding. SKConfigurableView inherits from both SKConfigurableModelProtocol and SKConfigurableLayoutProtocol, adding the preferredSize(limit:model:) requirement. The combined contract ensures that any conforming view can both receive data and declare its layout dimensions, which is essential for SectionKit's automated sizing system.

Can I use SKConfigurableView with UIKit views outside of UICollectionView?

Yes. While SectionKit primarily uses the protocol for collection view cells, any UIView can conform to SKConfigurableView. The protocol itself has no dependencies on UICollectionView; it merely defines a standard interface for model binding and size reporting. You can use it with table views, stack views, or custom container views, though you would need to manually call config(_:) and preferredSize(limit:model:) since SectionKit's automation is specific to its own section management system.

How does SectionKit calculate cell sizes without implementing UICollectionViewDelegateFlowLayout?

SectionKit intercepts the layout process by using SKCSingleTypeSection and related managers that query the cell's preferredSize(limit:model:) static method directly. According to the implementation in SKCSingleTypeSection.swift, the framework calculates sizes before cells are instantiated or dequeued, caching the results to avoid performance penalties. This eliminates the need for UICollectionViewDelegateFlowLayout methods like sizeForItemAt, as the protocol-based sizing is more precise and type-safe.

Is SKConfigurableView limited to UICollectionViewCell subclasses?

No. The protocol is designed to work with any UIView conforming type. While the most common use case is UICollectionViewCell subclasses, the protocol is also used for supplementary views, decoration views, and wrapped content views. The SKWrapperView class specifically exists to host plain UIView instances that conform to SKConfigurableView, allowing non-cell views to participate in SectionKit's layout system with full size calculation support.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →