UICollectionView: must be initialized with a non-nil layout parameter

IosUicollectionview

Ios Problem Overview


I added UICollectionView by code.
Now, the app crash with message: UICollectionView must be initialized with a non-nil layout parameter.
Do you have any idea to fix it?
CollectionCell is custom class of UICollectionViewCell.

@property (nonatomic, strong) UICollectionView* collectionView;

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.collectionView = [[UICollectionView alloc]init];
    [self.collectionView registerClass:[CollectionCell class] forCellWithReuseIdentifier:@"cell"];
    UICollectionViewFlowLayout* flowLayout = [[UICollectionViewFlowLayout alloc]init];
    flowLayout.itemSize = CGSizeMake(100, 100);
    [flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
    [self.collectionView setCollectionViewLayout:flowLayout];

    self.collectionView.frame = CGRectMake(0, 60, 320, 500);
    self.collectionView.backgroundColor = [UIColor whiteColor];
    self.collectionView.delegate = self;
    self.collectionView.dataSource = self;
    [self.view addSubview:self.eventCollection];
}

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    return 1;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return 20;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    CollectionCell* cell = [self.eventCollection dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
    cell.label.text = [NSString stringWithFormat:@"%d", indexPath.item];
    return cell;
}

Ios Solutions


Solution 1 - Ios

The crash is telling you pretty explicitly what is going wrong:

> UICollectionView must be initialized with a non-nil layout parameter.

If you check the documentation for UICollectionView, you'll find that the only initializer is initWithFrame:collectionViewLayout:. Further, in the parameters for that initializer, you'll see:

> frame > > The frame rectangle for the collection view, measured in points. The origin of the frame is relative to the superview in which you plan to add it. This frame is passed to the superclass during initialization. > > layout > > The layout object to use for organizing items. The collection view stores a strong reference to the specified object. Must not be nil.

I've bolded the important part. You must use initWithFrame:collectionViewLayout: to initialize your UICollectionView, and you must pass it a non-nil UICollectionViewLayout object.


One way to fix this, then, would be to simply change the order of initialization you do:

UICollectionViewFlowLayout* flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.itemSize = CGSizeMake(100, 100);
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:flowLayout];
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cell"];

Note that in the above example, I've assumed you want to use self.view.frame as the frame of self.collectionView. If that's not the case, insert whatever frame you want instead.

Solution 2 - Ios

Swift 3.0 and Swift 4.0

UICollectionView

The app crashed as soon as it launched when UICollectionView is initialised

initialize like below (above viewDidLoad)

let alarmCollectionView:UICollectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: UICollectionViewFlowLayout.init())
let layout:UICollectionViewFlowLayout = UICollectionViewFlowLayout.init()

In Method (inside viewDidLoad)

layout.scrollDirection = UICollectionViewScrollDirection.vertical
alarmCollectionView.setCollectionViewLayout(layout, animated: true)
alarmCollectionView.delegate = self
alarmCollectionView.dataSource = self
alarmCollectionView.backgroundColor = UIColor.clear
self.addSubview(alarmCollectionView)

Worked fine after initialising like this I am using Autolayout so using CGRect.zero or use your own CGRect

UICollectionViewController

In case if you are using UICollectionViewController instead of UICollectionView you need to add layout when initialization

 let  testNavController:UINavigationController = UINavigationController.init()
 let layout:UICollectionViewFlowLayout = UICollectionViewFlowLayout.init() 
 let collectionView:UICollectionViewController = UICollectionViewController.init(collectionViewLayout:layout )              
 testNavController.pushViewController(collectionView, animated: true)

Solution 3 - Ios

Just a swift version of Riley Avron's answer

    let layout = UICollectionViewFlowLayout()
    layout.itemSize = CGSizeMake(100, 100)
    let collectionView = UICollectionView(frame: CGRectZero, collectionViewLayout: layout)
    self.view.addSubview(collectionView)
    collectionView.delegate   = self
    collectionView.dataSource = self
    collectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "cellIdentifier")
    

Solution 4 - Ios

Swift 5 general solution

Can use UICollectionViewDelegateFlowLayout and don't forget to set your cell size

class YourViewController : UICollectionViewController, UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize.init(width: view.frame.width, height: 250)
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        self.collectionView!.register(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
    }
    // initialized with a non-nil layout parameter
    init() {
        super.init(collectionViewLayout: UICollectionViewFlowLayout())
    }    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Solution 5 - Ios

Swift 3.0, Swift 4.0 and Swift 5.0

It's work for me.

let collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: UICollectionViewFlowLayout.init())

In Method (inside viewDidLoad)

if let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
    flowLayout.scrollDirection = .horizontal
}

Solution 6 - Ios

In Swift

var collectionView: UICollectionView!
let layout = UICollectionViewFlowLayout()
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
layout.scrollDirection = .vertical
view.addSubview(collectionView)

Solution 7 - Ios

don't setCollectionViewLayout liked this:

[self.collectionView setCollectionViewLayout:flowLayout];

try to set when init:

[[UICollectionView alloc] initWithFrame:frame collectionViewLayout:defaultLayout];

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionkusumoto_teruyaView Question on Stackoverflow
Solution 1 - IosravronView Answer on Stackoverflow
Solution 2 - IosKoushikView Answer on Stackoverflow
Solution 3 - IosWilliam HuView Answer on Stackoverflow
Solution 4 - IoscandylineView Answer on Stackoverflow
Solution 5 - IosJohn CorderView Answer on Stackoverflow
Solution 6 - IosSourabh KumbharView Answer on Stackoverflow
Solution 7 - IosSemyonView Answer on Stackoverflow