이번 과제로 schoolfood 주문 화면 만들기였다.
하고나서 보니 stepper로 수량 늘리기, alert띄우기, textfiled로 입력한 값이 충전금액으로 넘어가는것은 잘 구현이 되었는데 충전금액이 저장되어 계속 더해지는게 아니라 초기화가 됐다!
lable값을 엉망으로 줘서 총 충전금액과 결제 금액의 값이 오류가 나네?
lable이 왜 틀렸는지 다시 보았더니 lable을 스토리보드에 배치하고 그 값은 코드로 구성했어야했는데, 그냥 바로 이름만 바꿔서 넣었다!
그러니 당연히 충전금액을 표시할때 조건문이 실행이 안될수밖에;
uilable에 int값 바로 대입한 멍청이..🥺 다른 사람들 코드랑 스승님 코드 보니까 내가 지금까지 수업을 제대로 이해를 못했구나..
올려주신 영상과 코드를 보면서 똑같이 따라해보고 구현 방법에 대해 다시 공부해보고 중요하다 싶은 부분들을 정리해서 올려본다.
//OrderViewController.swift
@IBOutlet weak var orderTableView: UITableView!
@IBOutlet weak var walletLabel: UILabel!
@IBOutlet weak var totalPriceLabel: UILabel!
var totalPrice = 0 {
willSet { totalPriceLabel.text = "\(newValue.toDecimalFormat())원" }
}
var wallet = 0 {
willSet { walletLabel.text = "\(newValue.toDecimalFormat())원"}
}
var balance: Int {
return wallet - totalPrice
}
var quantities = [0, 0, 0, 0]
위 코드 중 먼저 var totalPrice!
//Int+Extension.swift
import Foundation
extension Int {
func toDecimalFormat() -> String {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
guard let price = formatter.string(for: self)
else {
return "Formatting Error"
}
return price
}
}
위의 코드는 Int+Extension.swift파일에 있는 코드이다. extension에 Int는 self로 들어가게 된다. 그래서 number가 아닌 경우 실패할때 "Formatting Error"를 나타내준다. 맞게 나오면 price로 값이 출력된다.
위 코드를 만약 viewcontroller에 넣었다면,
//Int+Extension.swift
func toDecimalFormat(Int) -> String {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
guard let price = formatter.string(for: number)
else {
return "Formatting Error"
}
return price
}
위와 같이 고쳐주고 아까 var totalPrice를 고쳐주면 된다.
var totalPrice = 0 {
willSet { totalPriceLabel.text = "\(toDecimalFormat(number: newvalue))원" }
}
이렇게 해주면 이 함수를 int에 다 사용할수 있게 된다.
var balance: Int {
return wallet - totalPrice
}
이건 총 충전금액 - 총 결제금액 부분
var quantities = [0, 0, 0, 0]
이건 메뉴가 4개여서 이렇게 값을 넣어준거고 메뉴 개수를 추가해줄때마다 카운트를 할 수 있게 한것! 왜 난 이런 생각을 못하지 🤔
👇 아래의 코드는 내가 제일 어려워했던 부분을 알려주신 코드!
//OrderViewController.swift
@IBAction func didTapPayBarButtonItem(_ sender: UIBarButtonItem) {
guard totalPrice > 0 else {
present(UIAlertController.nothingToPay(), animated: true)
return
}
present(balance >= 0 ? paymentAlertController() : UIAlertController.insuffientMoney(balance: balance), animated: true)
}
@IBAction func didTapWalletBarButtonItem(_ sender: UIBarButtonItem) {
present(rechargeAlertController(), animated: true)
}
@IBAction func didTapResetButton(_ sender: UIButton) {
resetAll()
}
func resetAll() { //여기는 위에 설명했던것들
totalPrice = 0
wallet = 0
quantities = [0, 0, 0, 0]
orderTableView.reloadData()
}
}
//OrderViewController.swift
present(balance >= 0 ? paymentAlertController() : UIAlertController.insuffientMoney(balance: balance), animated: true)
위에 balance가 0 보다 크면 paymentAlertController() 을 실행하고, 0보다 작으면 insuffientMoney를 실행한다.
//OrderViewController.swift
extension OrderViewController {
func paymentAlertController() -> UIAlertController {
return UIAlertController.payment(totalPrice: totalPrice,
handler: { [weak self] in
guard let self = self else { return }
let balance = self.balance
self.resetAll()
self.wallet = balance
})
}
self.resetAll()을 해주는 이유는 결제가 성공하면 금액 부분을 초기화를 해줘야하기 때문! 또, 만약 위의 balnace에 금액이 남아 있었다고 한다면,
결제를 하고 나서 남은 금액을 기억해야하기 때문에 self.resetall()을 하면 다 0으로 바꾼 후 self.wallet = balance을 해주면 원래 금액을 넣어주게 된다.
UIAlertController+Extension.swift
//UIAlertController+Extension.swift
import UIKit
extension UIAlertController {
static func nothingToPay() -> UIAlertController {
let alertController = UIAlertController(title: "상품 없음", message: "먼저 상품을 추가하세요", preferredStyle: .alert)
let confirmAction = UIAlertAction(title: "확인", style: .default)
alertController.addAction(confirmAction)
return alertController
}
static func insuffientMoney(balance: Int) -> UIAlertController {
let alertController = UIAlertController(title: "잔액 부족", message: "\(abs(balance).toDecimalFormat())원이 모자랍니다", preferredStyle: .alert)
let confirmAction = UIAlertAction(title: "확인", style: .default)
alertController.addAction(confirmAction)
return alertController
}
static func payment(totalPrice: Int, handler: @escaping () -> Void) -> UIAlertController {
let alertController = UIAlertController(title: "결제", message: "총 \(totalPrice.toDecimalFormat())원을 결제 하시겠습니까?", preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "취소", style: .cancel)
let confirmAction = UIAlertAction(title: "확인", style: .default) { _ in handler() }
alertController.addAction(cancelAction)
alertController.addAction(confirmAction)
return alertController
}
static func recharge(handler: @escaping (Int) -> Void) -> UIAlertController {
let alertController = UIAlertController(title: "지갑", message: "얼마를 충전할까요?", preferredStyle: .alert)
alertController.addTextField { textField in
textField.keyboardType = .numberPad
}
let cancelAction = UIAlertAction(title: "취소", style: .cancel)
let confirmAction = UIAlertAction(title: "확인", style: .default) { _ in
guard let text = alertController.textFields?.first?.text,
let amount = Int(text) else { return }
handler(amount)
}
alertController.addAction(cancelAction)
alertController.addAction(confirmAction)
return alertController
}
}
코드에 label을 추가하고 다른 곳에서 텍스트라던가, 색을 바꾸고 싶은 경우 해당 태그 번호를 가진
새로운 객체를 만들고, 설정을 바꾸면 이용가능.
// ViewDidLoad
// label 생성
let label = UILabel()
// 기본 셋팅
label.frame.size = CGSize(width: 100, height: 50)
label.text = "yjpotato!"
label.textColor = .black
label.center = self.view.center
// 태그 지정
label.tag = 1
// 화면에 추가
self.view.addSubview(label)
@IBAction func btnTagText(_ sender: UIButton) {
// 1.Tag로 지정
let label = self.view.viewWithTag(1) as! UILabel
label.text = "yjpotato!"
label.textColor = .blue
}
@IBOutlet weak var mainView: UIView!
@IBOutlet weak var subView: UIView!
@IBOutlet weak var lbTagLable: UILabel!
override func viewDidLoad() {
label.tag = 1
}
// Tag로 지정
let label = mainView.viewWithTag(1) as! UILabel
label.text = "yjpotato!"
// OrderTableViewCell.swift
import UIKit
protocol OrderTableViewCellDelegate: AnyObject {
func didTapStepper(amount: Int, quantity: Int, tag: Int)
}
class OrderTableViewCell: UITableViewCell {
// MARK: - Properties
@IBOutlet weak var mainImageView: UIImageView!
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var priceLabel: UILabel!
@IBOutlet weak var countLabel: UILabel!
@IBOutlet weak var quantityStepper: UIStepper!
weak var delegate: OrderTableViewCellDelegate?
private var menu: Menu?
var quantity = 0 {
willSet { countLabel.text = String(newValue) + "개" }
}
// OrderViewController.swift
extension OrderViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Menu.allCases.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "OrderTableViewCell", for: indexPath) as? OrderTableViewCell else { fatalError() }
let menu = Menu.allCases[indexPath.row]
let quantity = quantities[indexPath.row]
cell.tag = indexPath.row
cell.setData(menu: menu, quantity: quantity)
cell.delegate = self
return cell
}
willset은 프로퍼티 옵저버이다. 프로퍼티 값이 변경된 직후를 감지하는 것으로,
Model에서 갱신된 값을 View에 보여줄 때 사용하게 된다.
💡 클래스의 init()안에서 값을 할당할 때는 willSet이 호출되지 않는다. (초기화 이후부터 프로퍼티를 감시하기 때문!)
//OrderViewController.swift
var totalPrice = 0 {
willSet { totalPriceLabel.text = "\(newValue.toDecimalFormat())원" } // 총 결제 금액이 바뀔때마다 View의 Label을 업데이트
}
var wallet = 0 {
willSet { walletLabel.text = "\(newValue.toDecimalFormat())원"}
} // 내 지갑 금액이 바뀔때마다 View의 Label을 업데이트
//OrderTableViewCell.swift
weak var delegate: OrderTableViewCellDelegate?
private var menu: Menu?
var quantity = 0 {
willSet { countLabel.text = String(newValue) + "개" }
} //// stepper를 눌렀을때 Label을 업데이트
이번 과제로 느낀점!
1.강의 꼭 복습하면서 헷갈리면 다시 보기
2.책 공부하기
3.모르면 꼭 물어보기..!