当UICollectionView和UICollectionViewCell在XIB文件中时,子视​​图为nil

时间:2018-02-02 11:28:01

标签: swift uiview uicollectionview uicollectionviewcell xib

Hi there! I've created a sample project that shows my problem exactly. Click to download!

我创建了一个包含UICollectionViewCell子类的应用,它包含一个ImageView作为子视图。它还有一个包含视图的XIB文件。

当我在UICollectionViewCell中直接嵌入UICollectionView时使用此ViewController时,单元格工作正常。这是包含注册单元格的代码的 WorkingViewController 的代码:

class WorkingViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
  @IBOutlet weak var collectionView: UICollectionView!

  override func viewDidLoad() {
    super.viewDidLoad()

    let cellNib = UINib(nibName: "ImageCell", bundle: nil)
    collectionView.register(cellNib, forCellWithReuseIdentifier: "ImageCell")

    collectionView.reloadData()
  }

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
  }

  func randomInt(min: Int, max: Int) -> Int {
    return Int(arc4random_uniform(UInt32(max - min + 1))) + min
  }

  func numberOfSections(in collectionView: UICollectionView) -> Int {
    return 1
  }

  func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return 100
  }

  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCell", for: indexPath) as? ImageCell else {
      fatalError("Could not load cell")
    }

    let randomNumber = randomInt(min: 1, max: 10)
    cell.imageView.image = UIImage(named: "stockphoto\(randomNumber)")

    return cell
  }
}

现在将 Storyboard入口点移到 BuggyViewController 。此处UICollectionView未直接嵌入。它包含在UIView中,也包含XIB。这是该视图的代码,包含从之前注册的单元格:

class DetailView: UIView, UICollectionViewDelegate, UICollectionViewDataSource {
  @IBOutlet var contentView: UIView!
  @IBOutlet weak var collectionView: UICollectionView!

  override init(frame: CGRect) {
    super.init(frame: frame)

    setup()
  }

  required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)

    setup()
  }

  private func setup() {
    Bundle.main.loadNibNamed("DetailView", owner: self, options: nil)

    self.addSubview(self.contentView)
    self.contentView.frame = self.bounds
    self.autoresizingMask = [.flexibleWidth, .flexibleHeight]

    collectionView.delegate = self
    collectionView.dataSource = self

    let cellNib = UINib(nibName: "ImageCell", bundle: nil)
    collectionView.register(cellNib, forCellWithReuseIdentifier: "ImageCell")
    collectionView.register(ImageCell.self, forCellWithReuseIdentifier: "ImageCell")

    collectionView.reloadData()
  }

  func randomInt(min: Int, max: Int) -> Int {
    return Int(arc4random_uniform(UInt32(max - min + 1))) + min
  }

  func numberOfSections(in collectionView: UICollectionView) -> Int {
    return 1
  }

  func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return 100
  }

  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCell", for: indexPath) as? ImageCell else {
      fatalError("Could not load cell")
    }

    let randomNumber = randomInt(min: 1, max: 10)
    cell.imageView.image = UIImage(named: "stockphoto\(randomNumber)")

    return cell
  }
}

但是这会导致DetailView第55行出错:

  

线程1:致命错误:在展开时出乎意料地发现nil   可选值

所以这里单元格的imageView突然变为零,这让我觉得我在注册单元格或实例化时做错了。但我无法解决它。

1 个答案:

答案 0 :(得分:2)

您应该删除注册单元类的行:

collectionView.register(ImageCell.self, forCellWithReuseIdentifier: "ImageCell")

确实,您已经在Nib中定义了您的单元格,并应通过方法func register(_ nib: UINib?, forCellWithReuseIdentifier identifier: String)进行注册。通过cellClass方法注册它将返回nil。

正如Apple医生所述:

  

如果您以前使用相同的重用注册了类或nib文件   标识符,您在cellClass参数中指定的类将替换   旧条目。如果需要,可以为cellClass指定nil   从指定的重用标识符中取消注册该类。

这解释了为什么你没有。