UICollectionView
initialization
layout parameter
iOS development
Swift programming

UICollectionView must be initialized with a non-nil layout parameter

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

The crash UICollectionView must be initialized with a non-nil layout parameter occurs when you create a UICollectionView without providing a UICollectionViewLayout object. Unlike UITableView, a collection view requires a layout at init time because it needs to know how to position cells before displaying anything. This commonly happens when using init(frame:) instead of init(frame:collectionViewLayout:), when loading from a storyboard with a missing layout, or when a programmatic initializer passes nil.

The Crash

swift
1// This crashes immediately
2let collectionView = UICollectionView(frame: .zero)
3// *** Terminating app due to uncaught exception:
4// 'UICollectionView must be initialized with a non-nil layout parameter'

UICollectionView does not have an init(frame:) initializer. The only designated initializer is init(frame:collectionViewLayout:).

Fix 1: Programmatic Initialization (Most Common)

swift
1let layout = UICollectionViewFlowLayout()
2layout.itemSize = CGSize(width: 100, height: 100)
3layout.minimumInteritemSpacing = 10
4layout.minimumLineSpacing = 10
5
6let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
7collectionView.backgroundColor = .white
8collectionView.register(MyCell.self, forCellWithReuseIdentifier: "cell")

Always pass a layout object. UICollectionViewFlowLayout is the standard grid layout provided by UIKit.

Fix 2: In a UIViewController

swift
1class GalleryViewController: UIViewController {
2    private var collectionView: UICollectionView!
3
4    override func viewDidLoad() {
5        super.viewDidLoad()
6
7        let layout = UICollectionViewFlowLayout()
8        layout.itemSize = CGSize(width: 120, height: 120)
9        layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
10
11        collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
12        collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
13        collectionView.dataSource = self
14        collectionView.delegate = self
15        collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
16
17        view.addSubview(collectionView)
18    }
19}

Fix 3: UICollectionViewController

UICollectionViewController requires a layout in its initializer:

swift
1// WRONG — uses init(nibName:bundle:) which has no layout
2let vc = GalleryCollectionViewController()
3
4// CORRECT — pass a layout
5let layout = UICollectionViewFlowLayout()
6layout.itemSize = CGSize(width: 80, height: 80)
7let vc = GalleryCollectionViewController(collectionViewLayout: layout)
swift
1class GalleryCollectionViewController: UICollectionViewController {
2    // If using init() without parameters, provide a default layout
3    init() {
4        let layout = UICollectionViewFlowLayout()
5        layout.itemSize = CGSize(width: 100, height: 100)
6        super.init(collectionViewLayout: layout)
7    }
8
9    required init?(coder: NSCoder) {
10        super.init(coder: coder)
11    }
12}

Fix 4: Storyboard / Interface Builder

When using storyboards, the collection view layout is set in Interface Builder:

  1. Select the UICollectionView in the storyboard
  2. In the Attributes Inspector, verify "Layout" is set to "Flow" (not "Custom" with a nil class)
  3. If using a custom layout, ensure the class name is correct in the Identity Inspector

If the layout class cannot be found at runtime (typo, missing module), the collection view receives nil and crashes.

Fix 5: Loading from Nib with init(coder:)

swift
1class CustomCollectionView: UICollectionView {
2    required init?(coder: NSCoder) {
3        // The storyboard/nib provides the layout via init(coder:)
4        // This should work automatically IF the layout is configured in IB
5        super.init(coder: coder)
6    }
7
8    // If you need to override the layout after loading from nib:
9    override func awakeFromNib() {
10        super.awakeFromNib()
11        let newLayout = UICollectionViewFlowLayout()
12        newLayout.itemSize = CGSize(width: 150, height: 150)
13        collectionViewLayout = newLayout
14    }
15}

Changing Layout After Initialization

You can change the layout at any time after initialization:

swift
1// Animated layout change
2let newLayout = UICollectionViewFlowLayout()
3newLayout.itemSize = CGSize(width: 200, height: 200)
4
5collectionView.setCollectionViewLayout(newLayout, animated: true) { completed in
6    print("Layout transition completed: \(completed)")
7}
8
9// Immediate layout change (no animation)
10collectionView.collectionViewLayout = newLayout

Compositional Layout (iOS 13+)

Modern iOS uses UICollectionViewCompositionalLayout for complex layouts:

swift
1let layout = UICollectionViewCompositionalLayout { sectionIndex, environment in
2    let itemSize = NSCollectionLayoutSize(
3        widthDimension: .fractionalWidth(1.0 / 3.0),
4        heightDimension: .fractionalHeight(1.0)
5    )
6    let item = NSCollectionLayoutItem(layoutSize: itemSize)
7    item.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5)
8
9    let groupSize = NSCollectionLayoutSize(
10        widthDimension: .fractionalWidth(1.0),
11        heightDimension: .absolute(120)
12    )
13    let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
14
15    let section = NSCollectionLayoutSection(group: group)
16    return section
17}
18
19let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)

Custom Layout

swift
1class WaterfallLayout: UICollectionViewLayout {
2    override var collectionViewContentSize: CGSize {
3        // Return the total content size
4        return CGSize(width: collectionView?.bounds.width ?? 0, height: contentHeight)
5    }
6
7    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
8        // Return attributes for all items in the visible rect
9        return cachedAttributes.filter { $0.frame.intersects(rect) }
10    }
11
12    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
13        return cachedAttributes[indexPath.item]
14    }
15}
16
17// Use it
18let collectionView = UICollectionView(frame: .zero, collectionViewLayout: WaterfallLayout())

Common Pitfalls

  • Using init(frame:) or init(): UICollectionView only has init(frame:collectionViewLayout:) as its designated initializer. Calling any other init variant crashes.
  • UICollectionViewController without layout: Pushing MyCollectionVC() without a layout crashes. Always use MyCollectionVC(collectionViewLayout: layout) or override init() to provide a default.
  • Custom layout class not found in storyboard: If the layout class name in Interface Builder has a typo or the module is wrong, the layout resolves to nil at runtime.
  • Setting collectionViewLayout = nil: Assigning nil to collectionViewLayout after initialization also crashes. Always provide a valid layout object.
  • Forgetting to register cells: After fixing the layout crash, the next crash is usually cell not registered. Always call register(_:forCellWithReuseIdentifier:) before reloadData.

Summary

  • UICollectionView requires a non-nil UICollectionViewLayout at initialization — no exceptions
  • Use UICollectionView(frame:collectionViewLayout:) with a UICollectionViewFlowLayout or UICollectionViewCompositionalLayout
  • For UICollectionViewController, pass the layout in init(collectionViewLayout:)
  • In storyboards, verify the layout type and custom class are set correctly
  • Change layouts after init with setCollectionViewLayout(_:animated:) or direct assignment

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.