使用多个 UICollectionView 时,出现错误,“...必须使用非零布局初始化"; [英] With Multiple UICollectionView's, getting error, "... must be initialized with non-nil layout"

查看:19
本文介绍了使用多个 UICollectionView 时,出现错误,“...必须使用非零布局初始化";的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

I have recently started working with Swift, and I am trying to go from one UICollectionView on the page (which worked) up to two of them. I am getting the error

"Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'UICollectionView must be initialized with a non-nil layout parameter'".

What I've found thus far on Stack Overflow has been incorporated into my code, but I am still getting the error. I am at my wit's end, please help!

Where I've been:

  • I Started with this article on setting up the UICollectionView, and everything worked just fine.
  • Now to set up a second UICollectionView on the same screen, I followed the instructions in this article.
  • Everything seems okay, I get "Build Succeeded", followed promptly by a crash as the app starts to run. Error message says:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'UICollectionView must be initialized with a non-nil layout parameter'

  • Looking for that error in StackOverflow, I find this article (which deals with a single UICollectionView, rather than the two that I have).
  • I've implemented everything I can from that article, but I'm still getting the error, and am now out of ideas. My code is below, any help would be most greatly appreciated!

ViewController.swift:

import UIKit
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {

var collectionViewLeft = UICollectionView()                         // changed "let" to "var" so I can assign things to it in viewDidLoad()
var collectionViewRight = UICollectionView()
let collectionViewLeftIdentifier = "CollectionViewLeftCell"
let collectionViewRightIdentifier = "CollectionViewRightCell"

override func viewDidLoad() {

    super.viewDidLoad()

    let layoutLeft = UICollectionViewFlowLayout()                   // this is what **I would think** would be my non-nil layout
    layoutLeft.itemSize = CGSize(width: 100, height: 100)

    let layoutRight = UICollectionViewFlowLayout()
    layoutRight.itemSize = CGSize(width: 100, height: 100)

    collectionViewLeft = UICollectionView(frame: self.view.frame, collectionViewLayout: layoutLeft)
    collectionViewRight = UICollectionView(frame: self.view.frame, collectionViewLayout: layoutRight)

    collectionViewLeft.delegate = self
    collectionViewRight.delegate = self

    collectionViewLeft.dataSource = self
    collectionViewRight.dataSource = self

    self.view.addSubview(collectionViewLeft)
    self.view.addSubview(collectionViewRight)

    collectionViewLeft.register(UICollectionViewCell.self, forCellWithReuseIdentifier: collectionViewLeftIdentifier)
    collectionViewRight.register(UICollectionViewCell.self, forCellWithReuseIdentifier: collectionViewRightIdentifier)

}


let reuseIdentifierLeft = "cellLeft" // also enter this string as the cell identifier in the storyboard
let reuseIdentifierRight = "cellRight"

var itemsRight = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48"]
var itemsLeft = ["10", "20", "30", "40", "50", "60"]


// MARK: - UICollectionViewDataSource protocol

// tell the collection view how many cells to make
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

    if collectionView == self.collectionViewLeft {
            return self.itemsLeft.count

    } else if collectionView == self.collectionViewRight {
            return self.itemsRight.count
    } else {
        print("This is very bad")
        assert(false, "Passed collectionView is neither collectionViewLeft nor collectionViewRight -- ruh roh!")
        return 0
    }
}

// make a cell for each cell index path
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    if collectionView == self.collectionViewLeft {
        // get a reference to our storyboard cell
        let cellLeft = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifierLeft, for: indexPath as IndexPath) as! MyCollectionViewCell

        // Use the outlet in our custom class to get a reference to the UILabel in the cell
        cellLeft.myLeftLabel.text = self.itemsLeft[indexPath.item]
        cellLeft.backgroundColor = UIColor.red // make cell more visible in our example project

        return cellLeft
    } else if collectionView == self.collectionViewRight {
        let cellRight = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifierRight, for: indexPath as IndexPath) as! MyRightCollectionViewCell

        // Use the outlet in our custom class to get a reference to the UILabel in the cell
        cellRight.myRightLabel.text = self.itemsRight[indexPath.item]
        cellRight.backgroundColor = UIColor.green // make cell more visible in our example project

        return cellRight
    } else {
        print("This is very bad")
        assert(false, "Passed collectionView is neither collectionViewLeft nor collectionViewRight -- ruh roh!")

        // won't actually execute the following, but to keep the compiler happy...
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifierLeft, for: indexPath as IndexPath) as! MyCollectionViewCell
        return cell
    }
}

// MARK: - UICollectionViewDelegate protocol

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

    // handle tap events

    if collectionView == self.collectionViewLeft {
        print("You tapped cell #(indexPath.item) on the LEFT!")
    } else if collectionView == self.collectionViewRight {
        print("You tapped cell #(indexPath.item) on the RIGHT!")
    } else {
        print("This is very bad")
        assert(false, "Passed collectionView is neither collectionViewLeft nor collectionViewRight -- ruh roh!")
    }
}

}

MyCollectionViewCell.swift

import UIKit

class MyCollectionViewCell: UICollectionViewCell {

    @IBOutlet weak var myLeftLabel: UILabel!

}

class MyRightCollectionViewCell: UICollectionViewCell {

    @IBOutlet weak var myRightLabel: UILabel!

}

解决方案

My guess, you declare UICollectionViewController's with empty default init constructor as variables:

var collectionViewLeft = UICollectionView()
var collectionViewRight = UICollectionView()

Try to replace your variable declarations without constructors:

Edited code below: As @Paulw11 correctly noted in his answer below, it's better to use an implicitly unwrapped optional ! rather than ?

var collectionViewLeft: UICollectionView!
var collectionViewRight: UICollectionView!

Anyway, you are instantiate them in your viewDidLoad function with designated initialisers for UICollectionView.

And just a note, it's better to register custom class / xibs before UICollectionView is added as a subview. It's not critical right now, but may be a problem after refactoring & etc., because you code can call UICollectionView delegate or dataSource functions before you code registered custom classes for cells. Just move your code with calls to .register() above self.view.addSubview():

collectionViewLeft.register(UICollectionViewCell.self, forCellWithReuseIdentifier: collectionViewLeftIdentifier)
collectionViewRight.register(UICollectionViewCell.self, forCellWithReuseIdentifier: collectionViewRightIdentifier)

这篇关于使用多个 UICollectionView 时,出现错误,“...必须使用非零布局初始化";的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆