应配置的自定义 CollectionViewCell 的 ImageView 为 nil

Posted

技术标签:

【中文标题】应配置的自定义 CollectionViewCell 的 ImageView 为 nil【英文标题】:ImageView of a custom CollectionViewCell is nil when it should be configured 【发布时间】:2016-10-23 14:19:36 【问题描述】:

我有一个tableViewCell 和一个collectionViewcollectionView's cells 是自定义的,它们只包含一个imageView

Here is my test project

这里是DataSource 我的CollectionView class 所需的方法:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCell", for: indexPath) as! ImageCell

    let image = UIImage(named: listItems[indexPath.row])
    cell.testImageView.image = image

    return cell


func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
    return listItems.count

当我尝试为单元格的 imageView 设置图像时,我得到了这个error

致命错误:在展开可选值时意外发现 nil

我检查了image,不是nil,而是testImageView,当我尝试将图像设置为collectionViewCell 的testImageView 时出现此错误。 我该如何解决? 编辑1

这是从tableViewController 调用来填充collectionView 的listItem 的方法

func load(listItem: [String]) 
    self.listItems = listItem
    reloadData()


另外,如果我用这个从collectionView cellForItemAt indexPath 中删除代码,一切正常

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCell", for: indexPath)
let imageView = UIImageView(image:UIImage(named: listItems[indexPath.row]))

cell.backgroundView = imageView

【问题讨论】:

testImageView,它是作为 IBOutlet 从界面构建器添加的吗? 你连接了image view的插座吗? @Ahmad F 是的,它是 @Midhun MP 是的,我做到了 所以检查 listItems 数组,它是否已实例化并包含元素? 它必须被实例化,否则不会显示任何单元格。它也可以通过强制转换正确地出列。它可能为空的唯一方法是插座。重新启动 XCode 并检查插座是否已设置。确保没有错别字。确保插座很弱:@IBOutlet weak var testImageView: UIImageView? 【参考方案1】:

你弄错了你的两个视图控制器。您的 IB 插座连接到不同视图控制器中的单元。我的意思是你可以在连接到同一个 IBOutlet 的不同控制器中拥有多个视图,但在你的情况下,首先加载的那个没有连接,所以这就是它崩溃的原因。

这是您的插座连接到的单元格。

这是您尝试加载(但未将 IBOutlet 连接到图像视图):

【讨论】:

哦,真的,复制粘贴方法失败了)抱歉浪费了时间( @astrolka BTW,请注意,您混合 Objective-C 和 swift 的方式有点奇怪。这种方法有什么特别的原因吗? 当我尝试做同样的事情但在 obj-c 上没有调用任何数据源方法时,here for more info:D 这听起来绝对是个错误。你不应该无缘无故地混用 Objective-C 和 Swift。老实说,您的代码一团糟,我建议您重新开始。你没有得到正确的 MVC,你查看的是你的数据源。 MVC 的重点是您的数据和视图通过控制器进行通信。出于某种原因,所有这些都嵌入到表格视图中,这很奇怪。您的数据源方法没有被调用的原因是您可能忘记将控制器设置为表格视图的数据源 实际上我无法弄清楚如何将我的数据与控制器分开,这就是为什么我将数据存储在控制器中,据我所知这不是一个坏习惯,是吗?如果你给我一个如何使用 MVC 的好例子,我会很高兴的【参考方案2】:

以防万一您想改用代码..

import UIKit


class ImageCell : UICollectionViewCell 

    private var imageView: UIImageView!
    private var descLabel: UILabel!

    public var image: UIImage? 
        get 
            return self.imageView.image
        

        set 
            self.imageView.image = newValue
        
    

    public var imageDesc: String? 
        get 
            return self.descLabel.text
        

        set 
            self.descLabel.text = newValue
        
    

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

        self.initControls()
        self.setTheme()
        self.doLayout()
    

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

        self.initControls()
        self.setTheme()
        self.doLayout()
    

    override func awakeFromNib() 
        super.awakeFromNib()
    

    func initControls() 
        self.imageView = UIImageView()
        self.descLabel = UILabel()
    

    func setTheme() 
        self.imageView.contentMode = .scaleAspectFit

        self.descLabel.numberOfLines = 1
        self.descLabel.lineBreakMode = .byWordWrapping
        self.descLabel.textAlignment = .center
        self.descLabel.textColor = UIColor.black

        self.contentView.backgroundColor = UIColor.white
    

    func doLayout() 
        self.contentView.addSubview(self.imageView)
        self.contentView.addSubview(self.descLabel)

        self.imageView.leftAnchor.constraint(equalTo: self.contentView.leftAnchor, constant: 5).isActive = true
        self.imageView.rightAnchor.constraint(equalTo: self.contentView.rightAnchor, constant: -5).isActive = true
        self.imageView.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 0).isActive = true

        self.descLabel.leftAnchor.constraint(equalTo: self.contentView.leftAnchor, constant: 5).isActive = true
        self.descLabel.rightAnchor.constraint(equalTo: self.contentView.rightAnchor, constant: -5).isActive = true
        self.descLabel.topAnchor.constraint(equalTo: self.imageView.bottomAnchor, constant: 5).isActive = true
        self.descLabel.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -5).isActive = true

        for view in self.contentView.subviews 
            view.translatesAutoresizingMaskIntoConstraints = false
        
    



class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout 

    private var collectionView: UICollectionView!
    private var dataSource: Array<String>!

    override func viewDidLoad() 
        super.viewDidLoad()

        self.initDataSource()
        self.initControls()
        self.setTheme()
        self.registerClasses()
        self.doLayout()
    

    override func didReceiveMemoryWarning() 
        super.didReceiveMemoryWarning()
    

    func initDataSource() 
        self.dataSource = ["Image1", "Image2", "Image3", "Image4", "Image5", "Image6"]
    

    func initControls() 
        let layout = UICollectionViewFlowLayout()
        layout.itemSize = CGSize(width: 117, height: 125)
        layout.invalidateLayout()
        self.collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
        self.collectionView.delegate = self
        self.collectionView.dataSource = self
    

    func setTheme() 
        self.collectionView.backgroundColor = UIColor.clear

        self.edgesForExtendedLayout = UIRectEdge(rawValue: 0)
        self.view.backgroundColor = UIColor.blue
    

    func registerClasses() 
        self.collectionView.register(ImageCell.self, forCellWithReuseIdentifier: "ImageCellIdentifier")
    

    func doLayout() 
        self.view.addSubview(self.collectionView)

        self.collectionView.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
        self.collectionView.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
        self.collectionView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
        self.collectionView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true

        for view in self.view.subviews 
            view.translatesAutoresizingMaskIntoConstraints = false
        
    

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

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
        return self.dataSource.count
    

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCellIdentifier", for: indexPath) as! ImageCell

        let imageName = self.dataSource[indexPath.row]
        cell.image = UIImage(named: imageName)
        cell.imageDesc = imageName

        return cell
    

http://imgur.com/o7O7Plw

【讨论】:

【参考方案3】:

也许“testImageView”出口变量没有从界面构建器连接,或者没有带有reuseIdentifier“ImageCell”的CollectionViewCell。使用 LLDB po 命令检查 cell 是否为 nil。

【讨论】:

如果没有reuseIdentifier "ImageCell" 那么dequeCell方法会报错 已连接,重用标识符正常且单元格不为零,我真的无法弄清楚这里出了什么问题((( @astrolka 你的单元格是在 Storyboard 中还是在 nib/xib 文件中设计的? @IlyaLapan 在 Storyboard 中,几分钟后我将添加项目 @astrolka ...尝试从图像名称中删除“.png”,同时将它们添加到 listItems 数组中。我已经多次遇到这种错误。我认为这应该可行。

以上是关于应配置的自定义 CollectionViewCell 的 ImageView 为 nil的主要内容,如果未能解决你的问题,请参考以下文章

自定义配置集合 - 无法识别的元素“addService”

Feign自定义配置和编写Feign的Spring boot 插件

使用 UITableViewAutomaticDimension 显示多行标签的自定义单元格

Facebook Messenger 的自定义 URI 方案

地图注释的自定义标题

匹配单个特定 url 的自定义路由