错误:无法使用自定义单元格类设置 UITableViewCell 标签和图像!只能加载单元格样式的数据:字幕不是自定义的

Posted

技术标签:

【中文标题】错误:无法使用自定义单元格类设置 UITableViewCell 标签和图像!只能加载单元格样式的数据:字幕不是自定义的【英文标题】:Error: Cannot set UITableViewCell labels and images with custom cell class! Only able to load data with cell style: subtitle not custom 【发布时间】:2019-04-10 21:52:34 【问题描述】:

过去两周我一直在努力使我的 iphone 应用程序与自定义 UITableViewCell 类一起工作,并且无法使用自定义类在 tableview 单元格中设置标签或图像。我已经能够使用标准单元格类型的字幕为每个单元格设置 textLabel 和 detailTextLabel 以及图像。

当我尝试在界面构建器中创建自定义单元格时,我转到单元格属性,选择自定义作为单元格样式,并为其指定“单元格”标识符。在代码中,我创建了一个名为class DrinkListTableViewController: UITableViewController 的类。在同一个文件中,我创建了一个名为class DrinkTableViewCell: UITableViewCell 的自定义单元类以及一个名为struct Drink 的数据结构。我已经验证来自我的 api 调用的数据是好的并且按预期加载但是我只能使用cell.imageView?.image =cell.textLabel?.text =cell.detailTextLabel?.text = 设置单元格标签和图像,而我真的想使用我创建的自定义单元格类(请请参阅代码作为参考)。

import Foundation
import UIKit
import Alamofire

struct Drink 
    let id: String
    let name: String
    let description: String
    let amount: Float
    let image: UIImage

    init(data: [String: Any]) 
        self.id = data["id"] as! String
        self.name = data["name"] as! String
        //self.amount = data["amount"] as! Float
        self.amount = ((data["amount"] as? NSNumber)?.floatValue)!
        self.description = data["description"] as! String
        self.image = data["image"] as! UIImage
    


class DrinkTableViewCell: UITableViewCell 
    @IBOutlet weak var cellName: UILabel!
    @IBOutlet weak var cellAmount: UILabel!
    @IBOutlet weak var cellDescription: UILabel!
    @IBOutlet weak var cellImage: UIImageView!

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String!) 
        super.init(style: style, reuseIdentifier: reuseIdentifier)
    

    required init?(coder aDecoder: NSCoder) 
        fatalError("init(coder:) has not been implemented")
    



class DrinkListTableViewController: UITableViewController 

    var drinks: [Drink] = []

    override func viewDidLoad() 
        super.viewDidLoad()
        navigationItem.title = "Drink Selection"
        tableView.dataSource = self
        tableView.delegate = self
        //tableView.register(DrinkTableViewCell.self, forCellReuseIdentifier: "cell")

        tableView.register(DrinkTableViewCell.self as AnyClass, forCellReuseIdentifier: "cell")

        //tableView.register(UINib(nibName: "DrinkTableViewCell", bundle: Bundle.main), forCellReuseIdentifier: "cell")

        //tableView.estimatedRowHeight = 134
        //tableView.rowHeight = UITableView.automaticDimension

        fetchInventory  drinks in
            guard drinks != nil else  return 
            self.drinks = drinks!
            //print("Data from API call: ", self.drinks)
            //self.tableView.reloadData()
//            DispatchQueue.main.async  [weak self] in
//                self?.tableView.reloadData()
//            
        
    

    override func viewDidAppear(_ animated: Bool) 
        super.viewDidAppear(animated)
        DispatchQueue.main.async  [weak self] in
            self?.tableView.reloadData()
        
    


    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
            performSegue(withIdentifier: "pizzaSegue", sender: self.drinks[indexPath.row] as Drink)
        //trying another method below?
        //self.navigationController?.pushViewController(UIViewController() as! PizzaViewController, animated: true)
    



    override func prepare(for segue: UIStoryboardSegue, sender: Any?) 

        if segue.identifier == "pizzaSegue" 
            guard let vc = segue.destination as? PizzaViewController else  return 
            vc.pizza = sender as? Pizza
        
    

    private func fetchInventory(completion: @escaping ([Drink]?) -> Void) 
Alamofire.request("http://127.0.0.1:4000/inventory", method: .get)
        .validate()
        .responseJSON  response in
            guard response.result.isSuccess else  return completion(nil) 
            guard let rawInventory = response.result.value as? [[String: Any]?] else  return completion(nil) 
            let inventory = rawInventory.compactMap  pizzaDict -> Drink? in
                var data = pizzaDict!
                data["image"] = UIImage(named: pizzaDict!["image"] as! String)
                //print("Printing each item: ", Drink(data: data))
                //printing all inventory successful
                return Drink(data: data)
            
            completion(inventory)
    


    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int 
        return 1
    

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        print("ROWS: ", drinks.count)
        return drinks.count
    


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 

        //let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! DrinkTableViewCell

        //let cell = UITableViewCell(style: UITableViewCell.CellStyle.subtitle, reuseIdentifier: "cell")

        let cell:DrinkTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "cell") as! DrinkTableViewCell

        cell.cellName?.text = drinks[indexPath.row].name
        cell.cellAmount?.text = String(drinks[indexPath.row].amount)
        cell.cellDescription?.text = drinks[indexPath.row].description
        cell.cellImage?.image = drinks[indexPath.row].image

//        cell.imageView?.image = drinks[indexPath.row].image
//        cell.textLabel?.text = drinks[indexPath.row].name
//        cell.detailTextLabel?.text = drinks[indexPath.row].description
//
        //print(cell.textLabel?.text)
        //print(cell.detailTextLabel?.text)

        print(cell.cellName?.text as Any)
        //print(cell.cellImage?.image)
        return cell
    

     override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
     return 100.0
     


当使用cell.cellName?.text = drinks[indexPath.row].name 之类的自定义类设置单元格标签和图像时,应用程序不会崩溃,但 tableView 不会加载任何内容,例如在 tableView 中具有来自drinks.count 的部分数量的空白 tableView覆盖 func numberOfRowsInSection。请帮忙!

【问题讨论】:

为什么let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! DrinkTableViewCell 被注释掉了? let cell = UITableViewCell(style: UITableViewCell.CellStyle.subtitle, reuseIdentifier: "cell") 不起作用,因为它需要在您的代码中为 as! DrinkTableViewCell 您只是将其称为具有字幕样式的普通单元格 是的,你是对的,但我有它,所以在 tableView 单元格中加载了一些东西。使用let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! DrinkTableViewCell 并将单元格文本和图像设置为我制作的自定义名称的方式,只需加载一个空白的tableView 【参考方案1】:

我认为是因为你需要使用:

    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! DrinkTableViewCell

在您的代码中被注释掉,而不是:

    let cell = UITableViewCell(style: UITableViewCell.CellStyle.subtitle, reuseIdentifier: "cell")

如果这不起作用,请尝试将其添加到您的自定义单元格类中,如果它不起作用,这可能就是您最初将其注释掉的原因:

 override init(style: UITableViewCell.CellStyle, reuseIdentifier: String!) 
    super.init(style: style, reuseIdentifier: reuseIdentifier)


required init?(coder aDecoder: NSCoder) 
    fatalError("init(coder:) has not been implemented")

编辑:

让我们尝试不使用情节提要。

class PostCell: UITableViewCell 

//Declare items

let cellName = UILabel()
let cellAmount = UILabel()
let cellDescription = UILabel()
let cellImage = UIImageView()

//Setup the layouts of your items

func configureCustomCell() 

    contentView.backgroundColor = .clear

    contentView.addSubview(cellName)
    cellName.translatesAutoresizingMaskIntoConstraints = false
    cellName.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 25).isActive = true
    cellName.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10).isActive = true

    contentView.addSubview(cellAmount)
    cellAmount.translatesAutoresizingMaskIntoConstraints = false
    cellAmount.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 25).isActive = true
    cellAmount.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10).isActive = true

    contentView.addSubview(cellDescription)
    cellDescription.translatesAutoresizingMaskIntoConstraints = false
    cellDescription.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 10).isActive = true
    cellDescription.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10).isActive = true

    contentView.addSubview(cellImage)
    cellImage.translatesAutoresizingMaskIntoConstraints = false
    cellImage.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -5).isActive = true
    cellImage.widthAnchor.constraint(equalToConstant: 50).isActive = true
    cellImage.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -10).isActive = true



 //Get ready for use

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String!) 
    super.init(style: style, reuseIdentifier: reuseIdentifier)


required init?(coder aDecoder: NSCoder) 
    fatalError("init(coder:) has not been implemented")



那么只要确保你有'viewDidLoad':

tableView.register(DrinkTableViewCell.self as AnyClass, forCellReuseIdentifier: "DTVCell")

那么在' override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell' 我们应该可以做到:

let cell:UserMessagesCell = self.tableView.dequeueReusableCell(withIdentifier: "DTVCell") as! DrinkTableViewCell

并像这样使用:

cell.cellName.text = "name"

编辑:

有时单元格行高的大小会影响自定义单元格。尝试增加每行的高度以确保所有内容都适合,因为有时如果高度错误,您可能会得到空单元格。

 func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
    return 100

尝试使用 if 语句来避免 API 调用出现任何问题。

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    if self.drinks.count == 0 
        print("No Data Yet: ", drinks.count)
        return 0
     else 
           print("ROWS: ", drinks.count)
           return self.drinks.count
    

【讨论】:

我将第一个方法 let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! DrinkTableViewCell 注释掉了,因为它没有加载带有任何数据的 tableView 但我已经注释掉了第二个方法 ``` let cell = UITableViewCell(style: UITableViewCell.CellStyle .subtitle,reuseIdentifier: "cell") ``` 并添加了override initrequired init 并更改了我将标签和图像设置为 cell.cellName 和 cell.cellAmount 等的方式,但事实证明这不起作用要么:/ @AustinGriffith 您是否在情节提要中设置了单元标识符?另一种选择,它的代码要多一些,但如果您在类中构建项目而不是使用情节提要,则在制作自定义单元格时会更方便一些。如果你愿意,我可以用一个对你有用的完整示例来更新我的答案。 我确实已经在情节提要中设置了单元格标识符,我已经两次和三次检查了代码和情节提要中的标识符匹配。我很想看看你的例子!我已经完成了 ppl 在我的另一篇文章中概述的所有步骤,但似乎没有什么能让我得到我需要的结果。对我来说很奇怪,我可以使用字幕样式将数据加载到单元格中,但是当尝试以自定义方式进行时,它不会加载任何内容。 @AustinGriffith 进行了编辑,在您这样做之前,将let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! DrinkTableViewCell 切换为let cell:UserMessagesCell = self.tableView.dequeueReusableCell(withIdentifier: "UserMessagesCell") as! UserMessagesCell 好的,我尝试按照您在上面给出的编辑答案进行操作。我仍然得到一个带有空白单元格的空白 tableView。我已将let cell = 更改为let cell:DrinkTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "cell") as! DrinkTableViewCell,我在自定义单元格类中添加了func configureCustomCell()class DrinkTableViewCell: UITableViewCell,但我看不到此方法被调用的位置。我在viewDidLoad中也改了一行:tableView.register(DrinkTableViewCell.self as AnyClass, forCellReuseIdentifier: "cell")

以上是关于错误:无法使用自定义单元格类设置 UITableViewCell 标签和图像!只能加载单元格样式的数据:字幕不是自定义的的主要内容,如果未能解决你的问题,请参考以下文章

自定义集合单元格错误

自定义单元格:致命错误:在展开可选值时意外发现 nil

从自定义表格视图单元格类加载时如何调整单元格的高度?

如何禁用自定义单元格中的按钮?

具有错误背景颜色的自定义 UITableViewCell

Swift:自定义单元格中的 IBoutlets 为零