Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

쥬스메이커 [STEP 3] 제이티, Ari #135

Closed
wants to merge 29 commits into from
Closed
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
3d2a6da
feat: 재고수정 화면 진입시 Label, Stepper의 Value 연동 기능 구현
leeari95 Nov 1, 2021
1e85463
feat: FruitStore에서 Label과 Stepper의 값 연동 및 Stepper 터치 시 Label 값 변환 구현
HoneyCoding Nov 1, 2021
df7531a
feat: Stepper를 클릭시 재고가 계산되도록 기능 구현
leeari95 Nov 2, 2021
23a4bdc
fix: FruitStore의 잘못된 조건문 수정
HoneyCoding Nov 2, 2021
febd113
fix: 재고 부족시 재고수정으로 넘어갈 때 Label 반영 안되는 버그 수정
leeari95 Nov 2, 2021
bd2ac42
refactor: JuiceMakerViewController의 중복 코드를 빼주어 메소드 setupNextViewLabel…
HoneyCoding Nov 2, 2021
9b545cf
refactor: stepperTapped 내부 가독성을 위해 fruitLabelText 메소드 추가하여 리팩토링
leeari95 Nov 2, 2021
e71fa4f
fix: Storyboard에서 JuiceMakerViewController Scene의 Content Priority 충돌…
HoneyCoding Nov 2, 2021
b9d4c03
fix: Button titleLabel이 버튼의 너비에 fit되도록 설정, 글꼴 자동 업데이트 설정
leeari95 Nov 2, 2021
4864c3c
refactor: JuiceMakerViewController의 코드를 extension을 사용해 분리
HoneyCoding Nov 2, 2021
93bf54e
refactor: FruitStoreViewController 내부 extension으로 분리
leeari95 Nov 2, 2021
484a0a1
fix: Storyboard의 Stepper와 연결된 stepperTapped 메소드의 Sent Events 변경
HoneyCoding Nov 2, 2021
2b397db
chore: 의미없는 줄바꿈과 프로퍼티 삭제
leeari95 Nov 2, 2021
1fec18c
chore: 기존 코드에서 오버 스펙으로 구현한 부분 제거
HoneyCoding Nov 2, 2021
da64fc6
docs: README.md 파일 내부에 STEP 3 관련 내용 추가
leeari95 Nov 2, 2021
ccb8a10
docs: README.md 파일 수정하다가 빠진 STEP 2 내용 다시 추가
leeari95 Nov 2, 2021
ae7582e
refactor: 메소드 네이밍 동사로 시작하도록 수정
HoneyCoding Nov 4, 2021
3a3c801
docs: READMD.md 파일 내용 추가
leeari95 Nov 4, 2021
82c2aa5
refactor: chooseCalculator 메소드 내에서 switch 문 사용을 if 문 사용으로 수정
HoneyCoding Nov 4, 2021
119b6d6
refactor: currentStockLabelUpdate 메소드 이름을 동사로 수정
leeari95 Nov 4, 2021
288fe58
refactor: JuiceMakerViewController, JuiceMaker, FruitStore 리팩토링
HoneyCoding Nov 5, 2021
d8f244d
refactor: 기존에 Singleton 패턴을 삭제
leeari95 Nov 5, 2021
ba4de9c
feat: UIButton에 extension을 통해 메소드 추가 및 기존 코드 일부 수정
HoneyCoding Nov 5, 2021
6a7ae09
refactor: fruitLabelChanged 메소드 이름을 fruitStockChanged로 수정
leeari95 Nov 5, 2021
dc428fe
feat: FruitStoreViewController가 deinit될 때 Notification 제거 코드 추가
HoneyCoding Nov 5, 2021
981c869
docs: README.md 내부 개선사항 내용 추가
leeari95 Nov 5, 2021
abef023
docs: README.md 수정
leeari95 Nov 5, 2021
827e98b
docs: README.md 내부 수정
leeari95 Nov 5, 2021
4809668
docs: README.md 내부 오타와 UML 이미지 수정
leeari95 Nov 7, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 99 additions & 1 deletion JuiceMaker/JuiceMaker/Controller/FruitStoreViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,111 @@

import UIKit

// MARK: - Properties and Lifecycle, Transition
class FruitStoreViewController: UIViewController {

@IBOutlet weak var strawberryStockLabel: UILabel!
@IBOutlet weak var bananaStockLabel: UILabel!
@IBOutlet weak var pineappleStockLabel: UILabel!
@IBOutlet weak var kiwiStockLabel: UILabel!
@IBOutlet weak var mangoStockLabel: UILabel!

@IBOutlet weak var strawberryStockStepper: UIStepper!
@IBOutlet weak var bananaStockStepper: UIStepper!
@IBOutlet weak var pineappleStockStepper: UIStepper!
@IBOutlet weak var kiwiStockStepper: UIStepper!
@IBOutlet weak var mangoStockStepper: UIStepper!

override func viewDidLoad() {
super.viewDidLoad()
setUpFruitStepperValues()
}

@IBAction func cancelButtonTapped(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
}

// MARK: - Label and Stepper Values Setting
extension FruitStoreViewController {
@IBAction func stepperTapped(_ sender: UIStepper) {
switch sender {
case strawberryStockStepper:
strawberryStockLabel.text = fruitLabelText(value: sender.value)
changeFruitStock(fruit: .strawberry, value: sender.value)
case bananaStockStepper:
bananaStockLabel.text = fruitLabelText(value: sender.value)
changeFruitStock(fruit: .banana, value: sender.value)
case pineappleStockStepper:
pineappleStockLabel.text = fruitLabelText(value: sender.value)
changeFruitStock(fruit: .pineapple, value: sender.value)
case kiwiStockStepper:
kiwiStockLabel.text = fruitLabelText(value: sender.value)
changeFruitStock(fruit: .kiwi, value: sender.value)
case mangoStockStepper:
mangoStockLabel.text = fruitLabelText(value: sender.value)
changeFruitStock(fruit: .mango, value: sender.value)
default:
showNotificationAlert(message: Message.unknownError.description)
}
}

func fruitLabelText(value: Double) -> String {
return String(format: "%.0f", value)
}

func setUpFruitStepperValues() {
updateCurrentStockStepperValue(fruit: .strawberry, stepper: strawberryStockStepper)
updateCurrentStockStepperValue(fruit: .banana, stepper: bananaStockStepper)
updateCurrentStockStepperValue(fruit: .pineapple, stepper: pineappleStockStepper)
updateCurrentStockStepperValue(fruit: .kiwi, stepper: kiwiStockStepper)
updateCurrentStockStepperValue(fruit: .mango, stepper: mangoStockStepper)
}

func updateCurrentStockStepperValue(fruit: Fruit, stepper: UIStepper) {
do {
let stock = try FruitStore.shared.stock(fruit: fruit)
stepper.value = Double(stock)
} catch {
showNotificationAlert(message: Message.unknownError.description)
}
}
}

// MARK: Stepper Operation
extension FruitStoreViewController {
func changeFruitStock(fruit: Fruit, value: Double) {
let oldStockValue: Int
let newStockValue = Int(value)
do {
oldStockValue = try FruitStore.shared.stock(fruit: fruit)
chooseCalculator(fruit: fruit, oldStockValue: oldStockValue, newStockValue: newStockValue)
} catch {
showNotificationAlert(message: Message.unknownError.description)
}
}

func chooseCalculator(fruit: Fruit, oldStockValue: Int, newStockValue: Int) {
if oldStockValue < newStockValue {
let count = newStockValue - oldStockValue
calculateFruitStock(fruit: fruit, count: count, calculate: FruitStore.shared.addFruitStock)
} else {
let count = oldStockValue - newStockValue
calculateFruitStock(fruit: fruit, count: count, calculate: FruitStore.shared.subtractFruitStock)
}
}

func calculateFruitStock(fruit: Fruit, count: Int, calculate: (Fruit, Int) throws -> Void ) {
do {
try calculate(fruit, count)
} catch {
showNotificationAlert(message: Message.unknownError.description)
}
}

func showNotificationAlert(message: String, title: String = Text.ok.title) {
let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
let cancel = UIAlertAction(title: title, style: .cancel, handler: nil)
alert.addAction(cancel)
present(alert, animated: true, completion: nil)
}
}
139 changes: 93 additions & 46 deletions JuiceMaker/JuiceMaker/Controller/JuiceMakerViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

import UIKit

// MARK: - Properties and Lifecycle
class JuiceMakerViewController: UIViewController {

private let juiceMaker = JuiceMaker()

@IBOutlet weak var strawberryStockLabel: UILabel!
Expand All @@ -27,10 +27,69 @@ class JuiceMakerViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
updateFruitLabels()

setUpbuttonLabelFontAttributes()

NotificationCenter.default.addObserver(self, selector: #selector(fruitLabelChanged(notification:)), name: .changedFruitStockNotification, object: nil)
}
}

// MARK: - Setup Label and Button
extension JuiceMakerViewController {
func setUpbuttonLabelFontAttributes() {
orderStrawberryBananaJuiceButton.titleLabel?.adjustsFontForContentSizeCategory = true
orderMangoKiwiJuiceButton.titleLabel?.adjustsFontForContentSizeCategory = true
orderStrawberryJuiceButton.titleLabel?.adjustsFontForContentSizeCategory = true
orderBananaJuiceButton.titleLabel?.adjustsFontForContentSizeCategory = true
orderPineappleJuiceButton.titleLabel?.adjustsFontForContentSizeCategory = true
orderKiwiJuiceButton.titleLabel?.adjustsFontForContentSizeCategory = true
orderMangoJuiceButton.titleLabel?.adjustsFontForContentSizeCategory = true

orderStrawberryBananaJuiceButton.titleLabel?.adjustsFontSizeToFitWidth = true
orderMangoKiwiJuiceButton.titleLabel?.adjustsFontSizeToFitWidth = true
orderStrawberryJuiceButton.titleLabel?.adjustsFontSizeToFitWidth = true
orderBananaJuiceButton.titleLabel?.adjustsFontSizeToFitWidth = true
orderPineappleJuiceButton.titleLabel?.adjustsFontSizeToFitWidth = true
orderKiwiJuiceButton.titleLabel?.adjustsFontSizeToFitWidth = true
orderMangoJuiceButton.titleLabel?.adjustsFontSizeToFitWidth = true
}

func updateFruitLabels() {
currentStockLabelUpdate(fruit: .strawberry, label: strawberryStockLabel)
currentStockLabelUpdate(fruit: .banana, label: bananaStockLabel)
currentStockLabelUpdate(fruit: .pineapple, label: pineappleStockLabel)
currentStockLabelUpdate(fruit: .kiwi, label: kiwiStockLabel)
currentStockLabelUpdate(fruit: .mango, label: mangoStockLabel)
}

func currentStockLabelUpdate(fruit: Fruit, label: UILabel) {
do {
let stock = try FruitStore.shared.stock(fruit: fruit)
label.text = stock.description
} catch let error as RequestError {
showNotificationAlert(message: error.errorDescription)
} catch {
showNotificationAlert(message: Message.unknownError.description)
}
}

func fruitlabel(of fruit: Fruit) -> UILabel {
switch fruit {
case .strawberry:
return strawberryStockLabel
case .banana:
return bananaStockLabel
case .pineapple:
return pineappleStockLabel
case .kiwi:
return kiwiStockLabel
case .mango:
return mangoStockLabel
}
}
}

// MARK: - Order Juice
extension JuiceMakerViewController {
@IBAction func orderJuiceButtonTapped(_ sender: UIButton) {
let juice: Juice

Expand Down Expand Up @@ -70,48 +129,6 @@ class JuiceMakerViewController: UIViewController {
}
}

@objc func fruitLabelChanged(notification: Notification) {
guard let fruit = notification.object as? Fruit else {
showNotificationAlert(message: Message.unknownError.description)
return
}
currentStockLabelUpdate(fruit: fruit, label: fruitlabel(of: fruit))
}

func updateFruitLabels() {
currentStockLabelUpdate(fruit: .strawberry, label: strawberryStockLabel)
currentStockLabelUpdate(fruit: .banana, label: bananaStockLabel)
currentStockLabelUpdate(fruit: .pineapple, label: pineappleStockLabel)
currentStockLabelUpdate(fruit: .kiwi, label: kiwiStockLabel)
currentStockLabelUpdate(fruit: .mango, label: mangoStockLabel)
}

func currentStockLabelUpdate(fruit: Fruit, label: UILabel) {
do {
let stock = try FruitStore.shared.stock(fruit: fruit)
label.text = stock.description
} catch let error as RequestError {
showNotificationAlert(message: error.errorDescription)
} catch {
showNotificationAlert(message: Message.unknownError.description)
}
}

func fruitlabel(of fruit: Fruit) -> UILabel {
switch fruit {
case .strawberry:
return strawberryStockLabel
case .banana:
return bananaStockLabel
case .pineapple:
return pineappleStockLabel
case .kiwi:
return kiwiStockLabel
case .mango:
return mangoStockLabel
}
}

func showNotificationAlert(message: String, title: String = Text.ok.title) {
let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
let cancel = UIAlertAction(title: title, style: .cancel, handler: nil)
Expand All @@ -127,10 +144,40 @@ class JuiceMakerViewController: UIViewController {
alert.addAction(okAction)
present(alert, animated: true, completion: nil)
}

}

// MARK: - Transition
extension JuiceMakerViewController {
private func presentFruitStoreViewController(_ action: UIAlertAction) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

파라미터로 action 은 왜 받는건가요?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let okAction = UIAlertAction(title: Text.ok.title, style: .default, handler: presentFruitStoreViewController)

private func presentFruitStoreViewController(_ action: UIAlertAction) {
// 내부 코드 구현
}
  • UIAlertAction의 이니셜라이저는 handler로 받는 클로저가 UIAlertAction 파라미터를 받도록 되어 있습니다. handler로 presentFruitStoreViewController 메소드를 전달해줄 때 해당 메소드에서 action을 파라미터로 받지 않으면 문법적 오류가 발생하여 이렇게 구현해주었습니다!
  • presentFruitStoreViewController 메소드에 action 파라미터를 받지 않도록 구현하려면 아래와 같이 구현할 수도 있습니다.
let okAction = UIAlertAction(title: Text.ok.title, style: .default) { action in
    presentFruitStoreViewController()
}

private func presentFruitStoreViewController() {
// 내부 코드 구현
}

guard let viewController = self.storyboard?.instantiateViewController(withIdentifier: "FruitStoreViewController") else { return }
guard let viewController = self.storyboard?.instantiateViewController(withIdentifier: "FruitStoreViewController") as? UINavigationController else { return }
self.present(viewController, animated: true, completion: nil)
guard let nextViewController = viewController.topViewController as? FruitStoreViewController else { return }
setupNextViewLabel(of: nextViewController)
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let navigationController = segue.destination as? UINavigationController else { return }
guard let nextViewController = navigationController.topViewController as? FruitStoreViewController else { return }
setupNextViewLabel(of: nextViewController)
}

func setupNextViewLabel(of nextViewController: FruitStoreViewController) {
nextViewController.loadViewIfNeeded()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • loadViewIfNeeded method 가 무슨 역할을 하나요?
  • 왜 외부에서 해당 viewcontroller 를 설정해주나요?

nextViewController.strawberryStockLabel.text = strawberryStockLabel.text
nextViewController.bananaStockLabel.text = bananaStockLabel.text
nextViewController.pineappleStockLabel.text = pineappleStockLabel.text
nextViewController.kiwiStockLabel.text = kiwiStockLabel.text
nextViewController.mangoStockLabel.text = mangoStockLabel.text
}
}

// MARK: - Notification
extension JuiceMakerViewController {
@objc func fruitLabelChanged(notification: Notification) {
guard let fruit = notification.object as? Fruit else {
showNotificationAlert(message: Message.unknownError.description)
return
}
currentStockLabelUpdate(fruit: fruit, label: fruitlabel(of: fruit))
}
}
4 changes: 2 additions & 2 deletions JuiceMaker/JuiceMaker/Model/FruitStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ class FruitStore {
guard let oldFruitCount = fruitBasket[fruit] else {
throw RequestError.fruitNotFound
}
guard count <= oldFruitCount else {
let newFruitCount = calculator(oldFruitCount, count)
guard newFruitCount >= 0 else {
throw RequestError.fruitStockOut
}
let newFruitCount = calculator(oldFruitCount, count)
fruitBasket[fruit] = newFruitCount

NotificationCenter.default.post(name: .changedFruitStockNotification, object: fruit)
Expand Down
14 changes: 2 additions & 12 deletions JuiceMaker/JuiceMaker/Model/Text.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,11 @@ enum Text {
case ok

var title: String {
return localizedTitle(key: self.key)
}

private var key: String {
switch self {
case .cancel:
return "Cancel"
return "취소"
case .ok:
return "OK"
return "확인"
}
}

private func localizedTitle(key: String) -> String {
let bundle = Bundle.init(for: UIButton.self)
let title = bundle.localizedString(forKey: key, value: nil, table: nil)
return title
}
}
Loading