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 2] 제이티, Ari #119

Merged
merged 17 commits into from
Nov 2, 2021
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
68927c4
feat: 쥬스 주문버튼 터치 시 Alret 표시되는 기능 구현
leeari95 Oct 25, 2021
c8f2ac6
feat: 주문 버튼 터치시 재고가 있는 경우와 없는 경우에 대한 기능 구현
HoneyCoding Oct 25, 2021
e083fff
feat: 과일의 재고가 바뀔 때 마다 화면에 반영되도록 기능 구현
leeari95 Oct 25, 2021
293f811
refactor: HIG 지침에 따라 Alert의 선택지 문구 수정
HoneyCoding Oct 26, 2021
a560ab2
refactor: Fruit타입을 FruitStore 내부에서 외부로 이동
leeari95 Oct 26, 2021
57031d7
refactor: JuiceMakerViewController의 UILabel 프로퍼티 이름 수정
HoneyCoding Oct 26, 2021
eb48bef
refactor: JuiceMakerViewController 내부 메서드명 수정
leeari95 Oct 26, 2021
0331594
refactor: JuiceMakerViewController 내부 메소드 순서 변경
HoneyCoding Oct 26, 2021
8edd150
refactor: orderJuiceButtonTapped 메서드 분리 및 리팩토링
leeari95 Oct 26, 2021
b28fab2
chore: 불필요한 주석 제거
HoneyCoding Oct 26, 2021
5d1c1da
chore: mixFruit 메서드 내부에 에러 문구를 수정
leeari95 Oct 26, 2021
f7bb20f
docs: README.md 파일 내용 추가
HoneyCoding Oct 26, 2021
8bfece8
refactor: 문자열을 모아놓은 enum Text 추가 및 숫자를 문자열로 형변환 하는 코드 수정
HoneyCoding Oct 28, 2021
5f09d5c
refactor: Juice 타입 리팩토링 및 Text 타입 이름 수정
leeari95 Oct 28, 2021
d252b60
refactor: Alert 버튼의 타이틀을 따로 Text 타입으로 구현
HoneyCoding Oct 28, 2021
0484cd1
refactor: FruitStore 내부에 전역변수를 enum Const 타입으로 리팩토링
leeari95 Oct 28, 2021
494468c
refactor: JuiceMakerViewController 내부의 showOutOfStockAlert 메소드의 코드 일부…
HoneyCoding Oct 28, 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
121 changes: 119 additions & 2 deletions JuiceMaker/JuiceMaker/Controller/JuiceMakerViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,128 @@ import UIKit

class JuiceMakerViewController: UIViewController {

private let juiceMaker = JuiceMaker()

@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 orderStrawberryBananaJuiceButton: UIButton!
@IBOutlet weak var orderMangoKiwiJuiceButton: UIButton!
@IBOutlet weak var orderStrawberryJuiceButton: UIButton!
@IBOutlet weak var orderBananaJuiceButton: UIButton!
@IBOutlet weak var orderPineappleJuiceButton: UIButton!
@IBOutlet weak var orderKiwiJuiceButton: UIButton!
@IBOutlet weak var orderMangoJuiceButton: UIButton!

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
updateFruitLabels()

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

@IBAction func orderJuiceButtonTapped(_ sender: UIButton) {

Choose a reason for hiding this comment

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

모든 button 의 action method 를 개별로 구현할 때와 이렇게 하나에 구현할 때의 장단점은 무엇인가요?

let juice: Juice

switch sender {
case orderStrawberryBananaJuiceButton:
juice = .strawberryBanana
case orderMangoKiwiJuiceButton:
juice = .mangoKiwi
case orderStrawberryJuiceButton:
juice = .strawberry
case orderBananaJuiceButton:
juice = .banana
case orderPineappleJuiceButton:
juice = .pineapple
case orderKiwiJuiceButton:
juice = .kiwi
case orderMangoJuiceButton:
juice = .mango
default:
showNotificationAlert(message: "잘못된 접근입니다.")
return
}

mixFruit(juice: juice)
}

func mixFruit(juice: Juice) {
do {
try juiceMaker.mixFruit(juice: juice)
showNotificationAlert(message: "\(juice) 쥬스 나왔습니다! 맛있게 드세요!")
} catch RequestError.fruitStockOut {
showOutOfStockAlert()
} catch let error as RequestError {
showNotificationAlert(message: error.errorDescription)
} catch {
showNotificationAlert(message: "알 수 없는 에러가 발생했습니다.")
}
}

@objc func fruitLabelChanged(notification: Notification) {
guard let fruit = notification.object as? Fruit else {
showNotificationAlert(message: "알 수 없는 에러가 발생했습니다.")

Choose a reason for hiding this comment

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

코드 전반에 걸쳐서 "알수없는~" 이 문장이 반복해서 사용되는데 따로 관리할 수 있는 법은 없나요?

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 = String(stock)

Choose a reason for hiding this comment

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

CustomStringConvertible 을 채택해서 String(stock) 으로 표현해서 label.text 에서 사용한 이유가 있나요? stock.descriptionText 같은 스타일로 사용할 수도 있지 않나요?

} catch let error as RequestError {
showNotificationAlert(message: error.errorDescription)
} catch {
showNotificationAlert(message: "알 수 없는 에러가 발생했습니다.")
}
}

func fruitlabel(of fruit: Fruit) -> UILabel {

Choose a reason for hiding this comment

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

이 메소드는 어떤 역할을 하는 메소드인가요?

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 = "OK") {
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)
}

func showOutOfStockAlert() {
let alert = UIAlertController(title: nil, message: "재료가 모자라요. 재고를 수정할까요?", preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
let okAction = UIAlertAction(title: "OK", style: .default) { _ in

Choose a reason for hiding this comment

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

여기 message 나 title에 들어가는 문자열들을 따로 관리할 방법이 없나요?

Copy link
Member Author

Choose a reason for hiding this comment

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

enum으로 따로 분리하여 관리하도록 개선하였습니다! 감사합니다!

guard let viewController = self.storyboard?.instantiateViewController(withIdentifier: "FruitStoreView") else { return }

Choose a reason for hiding this comment

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

  • 재고 화면 view controller 는 왜 이름이 FruitStoreview 인가요?
  • 해당 함수를 따로 빼면 어떤가요?

Copy link
Member Author

Choose a reason for hiding this comment

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

해당 부분도 피드백 반영하여 개선해보았습니다 😄
오늘 시간내서 코드리뷰 해주셔서 정말 감사합니다! 많은 도움이 되었어요!!!!! 😊🙏🏻

self.present(viewController, animated: true, completion: nil)
}
alert.addAction(cancelAction)
alert.addAction(okAction)
present(alert, animated: true, completion: nil)
}


}

30 changes: 20 additions & 10 deletions JuiceMaker/JuiceMaker/Model/FruitStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,16 @@ import Foundation

private let defaultFruitCount = 10

enum Fruit: CaseIterable {
case strawberry
case banana
case pineapple
case kiwi
case mango
}

class FruitStore {

static let shared: FruitStore = FruitStore()

Choose a reason for hiding this comment

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

JuiceMaker에 FruitStore 객체를 외부에서 주입해주지 않고 singleton 으로 넣은 이유가 있나요?


enum Fruit: CaseIterable {
case strawberry
case banana
case pineapple
case kiwi
case mango
}

private var fruitBasket: [Fruit: Int]

init(count: Int = defaultFruitCount) {

Choose a reason for hiding this comment

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

defaultFruitCount 가 FruitStore 내에서만 쓰이는데 안에서 관리하는게 낫지 않을까요?

Expand All @@ -29,6 +27,13 @@ class FruitStore {
self.fruitBasket = Dictionary(uniqueKeysWithValues: zip(allFruits, fruitscount))
}

func stock(fruit: Fruit) throws -> Int {
guard let fruitStock = fruitBasket[fruit] else {
throw RequestError.fruitNotFound
}
return fruitStock
}

func addFruitStock(fruit: Fruit, count: Int) throws {
try changeAmount(count: count, of: fruit, by: +)
}
Expand All @@ -49,6 +54,8 @@ class FruitStore {
}
let newFruitCount = calculator(oldFruitCount, count)
fruitBasket[fruit] = newFruitCount

NotificationCenter.default.post(name: .changedFruitStockNotification, object: fruit)

Choose a reason for hiding this comment

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

NotificationCenter 를 사용해보셨군요
근데 stock 이 줄어들 때는 이벤트 알림을 안받나요?

Copy link
Member Author

Choose a reason for hiding this comment

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

아뇨 줄어들때도 알림을 받습니다!
subtractFruitStock, addFruitStock 메서드가 changeAmount 메서드를 활용하여 stock을 추가하거나 빼는 일을 하고 있습니다😁

}

func hasFruitStock(of fruit: Fruit, count fruitCountSubtracted: Int) -> Bool {
Expand All @@ -58,3 +65,6 @@ class FruitStore {
}


extension Notification.Name {
static let changedFruitStockNotification = Notification.Name("changeFruitStock")
}
22 changes: 13 additions & 9 deletions JuiceMaker/JuiceMaker/Model/JuiceMaker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,20 @@

import Foundation

fileprivate typealias Recipe = [FruitStore.Fruit: Int]
fileprivate typealias Recipe = [Fruit: Int]

enum Juice {
case strawberry
case banana
case kiwi
case pineapple
case strawberryBanana
case mango
case mangoKiwi
enum Juice: String, CustomStringConvertible {
case strawberry = "딸기"
case banana = "바나나"
case kiwi = "키위"
case pineapple = "파인애플"
case strawberryBanana = "딸바"
case mango = "망고"
case mangoKiwi = "망키"

var description: String {
return rawValue
}

fileprivate var recipe: Recipe {
switch self {
Expand Down
2 changes: 1 addition & 1 deletion JuiceMaker/JuiceMaker/Model/RequestError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import Foundation

enum RequestError: Error, LocalizedError {
enum RequestError: Error {
case wrongCount
case fruitNotFound
case fruitStockOut
Expand Down
Loading