使用多个UICollectionView,得到错误,“......必须使用非零布局初始化”

时间:2016-11-23 20:58:15

标签: ios swift uicollectionview

我最近开始使用Swift,我试图从页面上的一个UICollectionView(有效)到最多两个。我收到了错误

  

“由于未捕获的异常终止应用程序' NSInvalidArgumentException',原因:'UICollectionView必须使用非零布局参数初始化'”。

我在Stack Overflow上发现的内容已经整合到我的代码中,但我仍然收到错误。我在我的智慧结束,请帮助!

我去过的地方:

  • 我开始使用this article设置UICollectionView,一切正常。
  • 现在要在同一个屏幕上设置第二个UICollectionView,我按照this article中的说明进行操作。
  • 一切似乎都没问题,我得到了“Build Succeeded”,随着应用程序开始运行,发生了崩溃。错误消息说:

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

  • 在StackOverflow中查找该错误,我找到this article(它处理单个UICollectionView,而不是我所拥有的两个)。
  • 我已经从那篇文章中实现了我所能做到的一切,但我仍然遇到错误,现在我已经没有想法了。我的代码如下,任何帮助都将非常感谢!

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!

}

2 个答案:

答案 0 :(得分:3)

不要将空UICollectionView个对象分配给您的属性;无论如何你只是要扔掉它们,因为你没有提供布局而导致异常。在这种情况下,您可以使用隐式解包的可选项:

var collectionViewLeft: UICollectionView!                        
var collectionViewRight: UICollectionView!

答案 1 :(得分:3)

我的猜测是,您使用空的默认UICollectionViewController构造函数将init声明为变量:

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

尝试在没有构造函数的情况下替换变量声明:

  

以下编辑的代码:正如@ Paulw11在下面的回答中正确指出的那样,最好使用隐式解包的可选项!而不是?

var collectionViewLeft: UICollectionView!
var collectionViewRight: UICollectionView!

无论如何,您要在viewDidLoad函数中使用指定的UICollectionView初始值来实例化它们。

只需注意,最好在UICollectionView添加为子视图之前注册自定义类/ xib。它现在并不重要,但在重构后可能会出现问题。等等,因为您的代码可以在为单元格注册自定义类之前调用​​UICollectionView delegatedataSource函数。只需通过.register()以上self.view.addSubview()的调用移动您的代码:

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