我对Swift编程还很陌生,但是我无法在UITableView类中为单个UITableViewCell实例设置UILabel文本。
我创建了一个名为PizzaTableViewCell
的UITableViewCell自定义子类和一个名为PizzaListTableViewController
的自定义UITableView类。我正在尝试使用数组中的数据填充UITableView实例,该数组是通过对我的node.js服务器的API调用填充的。
我包括了我的UITableView子类,自定义UITablveViewCell类,数据的结构以及指向模拟器的屏幕快照的链接,该模拟器加载了我所做的事情。任何帮助将不胜感激!
我已验证数据已正确放入数组中,因为我可以在调用fetchInventory
方法之后打印内容。我已经可以使用
cell.textLabel?.text = pizzas[indexPath.row].name
连同数组中的图像一起:
cell.imageView?.image = pizzas[indexPath.row].image
但是我在每个无法设置的单元格中还需要2个标签。我已经检查了IBOutlets
和情节提要标识符,它们与代码匹配。
class PizzaListTableViewController: UITableViewController {
var pizzas: [Pizza] = []
override func viewDidLoad() {
super.viewDidLoad()
//title you will see on the app screen at the top of the table view
navigationItem.title = "Drink Selection"
tableView.register(PizzaTableViewCell.self, forCellReuseIdentifier: "Pizza")
//tableView.estimatedRowHeight = 134
//tableView.rowHeight = UITableViewAutomaticDimension
fetchInventory { pizzas in
guard pizzas != nil else { return }
self.pizzas = pizzas!
print(self.pizzas)
//self.tableView.reloadData()
//print(self.pizzas)
DispatchQueue.main.async { [weak self] in
self?.tableView.reloadData()
}
}
} //end of viewDidLoad
private func fetchInventory(completion: @escaping ([Pizza]?) -> 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 -> Pizza? in
var data = pizzaDict!
data["image"] = UIImage(named: pizzaDict!["image"] as! String)
//print(data)
//print("CHECK")
print("Printing each item: ", Pizza(data: data))
//printing all inventory successful
return Pizza(data: data)
}
completion(inventory)
}
}
@IBAction func ordersButtonPressed(_ sender: Any) {
performSegue(withIdentifier: "orders", sender: nil)
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
//PRINTING ROWS 0 TWICE in console
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("ROWS", pizzas.count)
return self.pizzas.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: PizzaTableViewCell = tableView.dequeueReusableCell(withIdentifier: "Pizza", for: indexPath) as! PizzaTableViewCell
//cell.backgroundColor = Services.baseColor
//cell.pizzaImageView?.image = pizzas[indexPath.row].image
//THESE WORK BUT ARE A STATIC WAY OF SETTING THE CELLS
//CAN ONLY SET THE SELL WITH A SINGLE TEXT LABEL FROM THE DATA ARRAY
cell.imageView?.image = pizzas[indexPath.row].image
cell.textLabel?.text = pizzas[indexPath.row].name
//cell.textLabel?.text = pizzas[indexPath.row].description
//cell.textLabel?.text = "$\(pizzas[indexPath.row].amount)"
// cell.name?.text = pizzas[indexPath.row].name
// cell.imageView?.image = pizzas[indexPath.row].image
// cell.amount?.text = "$\(pizzas[indexPath.row].amount)"
// cell.miscellaneousText?.text = pizzas[indexPath.row].description
//print(cell.name?.text! as Any)
print(cell.imageView as Any)
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100.0
} //END OF
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "pizzaSegue", sender: self.pizzas[indexPath.row] as Pizza)
} //END OF override func tableView
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
}
} //END OF override preppare func
}
class PizzaListTableViewController: UITableViewController {
var pizzas: [Pizza] = []
override func viewDidLoad() {
super.viewDidLoad()
//title you will see on the app screen at the top of the table view
navigationItem.title = "Drink Selection"
tableView.register(PizzaTableViewCell.self, forCellReuseIdentifier: "Pizza")
//tableView.estimatedRowHeight = 134
//tableView.rowHeight = UITableViewAutomaticDimension
fetchInventory { pizzas in
guard pizzas != nil else { return }
self.pizzas = pizzas!
print(self.pizzas)
//self.tableView.reloadData()
//print(self.pizzas)
DispatchQueue.main.async { [weak self] in
self?.tableView.reloadData()
}
}
} //end of viewDidLoad
private func fetchInventory(completion: @escaping ([Pizza]?) -> 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 -> Pizza? in
var data = pizzaDict!
data["image"] = UIImage(named: pizzaDict!["image"] as! String)
//print(data)
//print("CHECK")
print("Printing each item: ", Pizza(data: data))
//printing all inventory successful
return Pizza(data: data)
}
completion(inventory)
}
}
@IBAction func ordersButtonPressed(_ sender: Any) {
performSegue(withIdentifier: "orders", sender: nil)
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
//PRINTING ROWS 0 TWICE in console
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("ROWS", pizzas.count)
return self.pizzas.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: PizzaTableViewCell = tableView.dequeueReusableCell(withIdentifier: "Pizza", for: indexPath) as! PizzaTableViewCell
//cell.backgroundColor = Services.baseColor
//cell.pizzaImageView?.image = pizzas[indexPath.row].image
//THESE WORK BUT ARE A STATIC WAY OF SETTING THE CELLS
//CAN ONLY SET THE SELL WITH A SINGLE TEXT LABEL FROM THE DATA ARRAY
cell.imageView?.image = pizzas[indexPath.row].image
cell.textLabel?.text = pizzas[indexPath.row].name
//cell.textLabel?.text = pizzas[indexPath.row].description
//cell.textLabel?.text = "$\(pizzas[indexPath.row].amount)"
// cell.name?.text = pizzas[indexPath.row].name
// cell.imageView?.image = pizzas[indexPath.row].image
// cell.amount?.text = "$\(pizzas[indexPath.row].amount)"
// cell.miscellaneousText?.text = pizzas[indexPath.row].description
//print(cell.name?.text! as Any)
print(cell.imageView as Any)
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100.0
} //END OF
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "pizzaSegue", sender: self.pizzas[indexPath.row] as Pizza)
} //END OF override func tableView
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
}
} //END OF override preppare func
}
struct Pizza {
let id: String
let name: String
let description: String
let amount: Float
//let amount: String
let image: UIImage
init(data: [String: Any]) {
//print("CHECK:: pizza.swift")
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
}
}
如上所述,我已经能够打印带有啤酒名称,图片,描述等的数据数组的内容。我试图打印到控制台
print(cell.name?.text)
设置后
cell.name?.text = pizzas[indexPath.row].name
但是它打印nil
,这是一个问题。我已经坚持了大约两个星期!
IBOutlets屏幕截图:
答案 0 :(得分:1)
我想我找到了您的问题,让我解释一下
您在这里做的是在UITableViewCell
的一个名为“ Root View Controller”的控制器中定义了一个自定义Storyboard
,这不是您的PizzaListTableViewController
的简单表达>
正如您所说,您对IBOutlets
现在当你说
tableView.register(PizzaTableViewCell.self, forCellReuseIdentifier: "Pizza")
在您的PizzaListTableViewController
中,您并未将其与单元格的UI链接,而仅将其与代码链接(仅当单元格没有xib时才使用)
现在您可以做什么来解决这个问题
解决方案1
PizzaTableViewCell
”的用户界面从“根视图控制器”移动到情节提要中/复制到PizzaListTableViewController
Reuse Identifier
tableView.register(PizzaTableViewCell.self, forCellReuseIdentifier: "Pizza")
,因为它会自动获得注册,所以这次不会给您带来错误IBOutlets
已连接解决方案2
为该单元格创建一个单独的Nib
(xib
)
现在您必须像这样在这里注册单元格
tableView.register(UINib(nibName: "PizzaTableViewCell", bundle: Bundle.main), forCellReuseIdentifier: "PizzaCell")
希望这会有所帮助。
答案 1 :(得分:0)
尝试一下
cell.name?.text = ...
cell.amount?.text = ...
cell.miscellaneousText?.text = ...
cell.pizzaImageView?.image = ...
如果仍然不起作用,请在设置其值时确保单元格和插座不为空。希望对您有帮助!
答案 2 :(得分:0)
在您的设置中确实发生了一些奇怪的事情。 如果您尝试使用与UITableViewCell默认属性相同的名称来命名IBOutlet,则会引发错误。您能够设置这些名称并成功构建的事实很奇怪。
从上面的屏幕截图中,您可以看到尝试执行此操作时发生的情况。
答案 3 :(得分:0)
确保在情节提要中设置了Table View Controller类。
确保在情节提要中设置了Table View Cell类。
确保所有插座均正确连接。
确保情节提要中提供了“表格视图单元格标识符”。
我的表视图控制器子类
我的表格视图单元格子类
cell.imageView?.image 和 cell.textLabel?.text 是表视图本身的可选属性。它们不是您设计的自定义单元的属性。
在XIB中设计表格视图单元格时,请使用 tableView.register(PizzaTableViewCell.self,forCellReuseIdentifier:“ Pizza”)。但是,当您在情节提要板上设计了单元格时,应该在情节提要中设置单元格重用标识符和单元格类。
我希望这会对您有所帮助。