问题描述
我是 Swift 初学者,我正在尝试制作一个用于订购食物的简单应用。用户可以通过设置食物name
、price
和serving
来添加新订单。添加订单后,该订单将在 tableView 上显示为 FoodTableViewCell
,并且用户可以在每个单元格中使用名为 stepper
的 UIStepper 更改服务。每个订单都是一个 FoodItem
,存储在一个名为 foodList
的数组中,您可以在 ShoppingListVC
的 tableView 中看到列出的所有订单。
我的问题是:当我在 stepper
上按“+”或“-”按钮时,我的 servingLabel
没有更改为相应的值。我尝试使用NotificationCenter
将服务值传递给 stepper
,并在 food.serving
之后使用委托模式将新值存储回 stepperValueChanged
。但是,似乎仍然存在一些错误。在网上浏览了很多解决方案后,我有点困惑。任何帮助表示赞赏。
更新
我删除了 NotificationCenter
和 addTarget
相关方法作为@Tarun Tyagi 的建议。现在我的 UIStepper 值变回 1,而servingLabels 显示不同数量的服务。由于 NotificationCenter 没有帮助,我如何将标签和步进值连接在一起?是否建议实现另一个委托?
这是我的代码(7 月 8 日更新):
食品
class FoodItem: Equatable {
static func == (lhs: FoodItem,rhs: FoodItem) -> Bool {
return lhs === rhs
}
var name: String
var price: Int
var serving: Int
var foodID: String
init(name: String,price: Int,serving: Int) {
self.name = name
self.price = price
self.serving = serving
self.foodID = UUID().uuidString
}
}
视图控制器
import UIKit
class ShoppingListVC: UIViewController,UITableViewDataSource,UITableViewDelegate {
var foodList = [FoodItem]()
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
...
for i in 1...5 {
let testItem = FoodItem(name: "Food\(i)",price: Int.random(in: 60...100),serving: Int.random(in: 1...10))
self.foodList.append(testItem)
}
}
// MARK: - Table view data source
...
func tableView(_ tableView: UITableView,cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "foodCell",for: indexPath) as! FoodTableViewCell
let food = foodList[indexPath.row]
cell.nameLabel.text = food.name
cell.priceLabel.text = "$\(String(food.price)) / serving"
cell.servingLabel.text = "\(String(food.serving)) serving"
cell.stepper.tag = indexPath.row
cell.delegate = self
return cell
}
}
// MARK: - FoodTableViewCellDelegate Method.
extension ShoppingListVC: FoodTableViewCellDelegate {
func stepper(_ stepper: UIStepper,at index: Int,didChangeValueto newValue: Double) {
let indexPath = IndexPath(item: index,section: 0)
guard let cell = tableView.cellForRow(at: indexPath) as? FoodTableViewCell else { return }
let foodToBeUpdated = foodList[indexPath.row]
print("foodToBeUpdated.serving: \(foodToBeUpdated.serving)")
foodToBeUpdated.serving = Int(newValue)
print("Value changed in VC: \(newValue)")
cell.servingLabel.text = "\(String(format: "%.0f",newValue)) serving"
}
}
TableViewCell
import UIKit
protocol FoodTableViewCellDelegate: AnyObject {
func stepper(_ stepper: UIStepper,didChangeValueto newValue: Double)
}
class FoodTableViewCell: UITableViewCell {
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var priceLabel: UILabel!
@IBOutlet weak var servingLabel: UILabel!
@IBOutlet weak var stepper: UIStepper!
weak var delegate: FoodTableViewCellDelegate?
@IBAction func stepperValueChanged(_ sender: UIStepper) {
sender.minimumValue = 1
servingLabel.text = "\(String(format: "%.0f",sender.value)) serving"
// Pass the new value to ShoppingListVC and notify which cell to update using tag.
print("sender.value: \(sender.value)")
delegate?.stepper(stepper,at: stepper.tag,didChangeValueto: sender.value)
}
override func awakeFromNib() {
super.awakeFromNib()
print(stepper.value)
}
}
解决方法
单元配置:
protocol FoodTableViewCellDelegate: AnyObject {
func stepper(sender: FoodTableViewCell)
}
@IBAction func stepperButtonTapped(sender: UIStepper) {
delegate?.stepperButton(sender: self)
stepperLabel.text = "\(Int(countStepper.value))"
}
控制器配置:
cellForRow:
cell.countStepper.value = Double(foodList[indexPath.row].serving);
cell.stepperLabel.text = "\(Int(cell.countStepper.value))"
委托方法:
func stepperButton(sender: FoodTableViewCell) {
if let indexPath = tableView.indexPath(for: sender){
print(indexPath)
foodList[sender.tag].serving = Int(sender.countStepper.value)
}
}
,
最初 FoodTableViewCell
是 UIStepper
值更改的唯一目标(查看 @IBAction
中的 FoodTableViewCell
)。
当您将单元格出列以在屏幕上显示时,您调用 -
cell.stepper.addTarget(self,action: #selector(stepperValueChanged(_:)),for: .valueChanged)
这会导致您的 ShoppingListVC
实例被添加为附加目标每次执行 cellForRow
调用。
需要解决的问题:
- 从两个类中删除所有与
NotificationCenter
相关的代码。 - 同时删除
cell.stepper.addTarget()
行。
这会让您更好地了解为什么会以这种方式发生。如果您仍然没有想要的东西,请使用这些更改更新您的问题。
更新
// Inside cellForRow
cell.stepper.value = food.serving
,
请检查 value stepper pod,它会对您有所帮助:Value stepper
集成 value stepper pod 并使用以下代码进行基本实现。
import ValueStepper
let valueStepper: ValueStepper = {
let stepper = ValueStepper()
stepper.tintColor = .whiteColor()
stepper.minimumValue = 0
stepper.maximumValue = 1000
stepper.stepValue = 100
return stepper
}()
override func viewDidLoad() {
super.viewDidLoad()
valueStepper.addTarget(self,action: "valueChanged:",forControlEvents: .ValueChanged)
}
@IBAction func valueChanged1(sender: ValueStepper) {
// Use sender.value to do whatever you want
}
它简化了自定义步进器植入。在table tableview中取出value stepper view并使用它。