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

时间:2019-04-10 21:52:35

标签: arrays swift xcode uitableview

过去2年来,我一直在努力让我的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中,其饮料中有来自section.count的部分tableView会覆盖func numberOfRowsInSection函数。请帮忙!

1 个答案:

答案 0 :(得分: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")

然后在'覆盖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
    }
}