【问题标题】:With Multiple UICollectionView's, getting error, "... must be initialized with non-nil layout"使用多个 UICollectionView,出现错误,“......必须使用非零布局初始化”
【发布时间】:2017-04-08 00:40:42
【问题描述】:

我最近开始使用 Swift,我正在尝试从页面上的一个 UICollectionView(有效)到其中两个。我收到错误

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

到目前为止,我在 Stack Overflow 上发现的内容已合并到我的代码中,但我仍然收到错误消息。我无能为力,请帮忙!

我去过的地方:

  • 我从this article 开始设置 UICollectionView,一切正常。
  • 现在要在同一屏幕上设置第二个 UICollectionView,我按照 this article 中的说明进行操作。
  • 一切似乎都很好,我得到“构建成功”,然后在应用程序开始运行时立即崩溃。错误信息说:

*** 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!

}

【问题讨论】:

    标签: ios swift uicollectionview


    【解决方案1】:

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

    var collectionViewLeft: UICollectionView!                        
    var collectionViewRight: UICollectionView!
    

    【讨论】:

    • 后续问题已发布here。相同的项目,新的错误。
    【解决方案2】:

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

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

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

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

    var collectionViewLeft: UICollectionView!
    var collectionViewRight: UICollectionView!
    

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

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

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

    【讨论】:

    • 太好了——谢谢!我的代表不足以计算赞成票(还没有?),但这似乎奏效了。
    • 不要担心赞成票,我们大多数人只是来帮忙的。祝你编程好运!
    • 我建议你使用一个隐式展开的可选!而不是 ?否则你必须不断地展开视图。如果视图 为零,那么这是一个严重的问题,并且没有合理的方法可以继续
    • 我同意@Paulw11,所以我根据他的建议更新了我的答案。
    • here 发布的后续问题 - 可能不同到足以保证成为一个单独的问题,但要跟进这个项目。一个错误消失了,另一个错误出现了。
    猜你喜欢
    • 2018-05-09
    • 2019-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-08
    • 1970-01-01
    • 2019-01-19
    • 1970-01-01
    相关资源
    最近更新 更多