---
# System prepended metadata

title: iOS_juice_maker README 작성 (Jason & Lust3r)

---

# iOS_juice_maker README 작성 (Jason & Lust3r)

----

<a href ="#1-Step1---쥬스 메이커 타입 정의">Step1 - 쥬스 메이커 타입 정의</a>
<a href ="#2-Step2---초기화면 기능구현">Step2 - 초기화면 기능구현</a>
<a href ="#3-Step3---재고 수정 기능구현">Step3 - 재고 수정 기능구현</a>

----
## 🗂️ 프로젝트 파일 구조
<img src = "https://user-images.githubusercontent.com/45708630/210944976-ffe0afcd-d73e-478b-ad73-efb36373d22a.png" width=1000 height=400>

---
## 🔖 역할 분배
|enum|역할|
|:---|:---|
|`Fruit`|과일 리스트를 Case별로 나누었습니다.|
|`SingleFruitJuice`|한 가지 종류의 과일 쥬스를 만들 수 있는 Case별로 나누었습니다.|
|`MixFruitJuice`|두 가지 종류의 과일 쥬스를 만들 수 있는 Case별로 나누었습니다.|
|`StockError`|재고가 없을 때 에러메세지를 출력할 수 있도록 Case별로 나누었습니다.|

|protocol|역할|
|:---|:---|
|Makeable|`JuiceMacker`가 제조하는 역할만 할 수 있도록 메서드를 정의하였습니다.|
|Computable|`Calculator`가 계산기처럼 사칙연산의 역할만 할 수 있도록 메서드를 정의하였습니다.|
|SendDataDelegate|`FruitViewController`에서 초기 재고 값을 보여줄 수 있도록 메서드를 정의하였습니다.|

|struct & Class|역할|
|:---|:---|
|`JuiceMaker`|제일 상위 모듈로 ViewController에서 요청하는 행위를 진행할 수 있도록</br> 구현하였습니다.|
|`FruitStore`|Singleton 패턴을 적용하여 재고관리를 진행하는 클래스 타입의 모델입니다.|
|`Calculator`|SOLID의 DIP에 맞추어 계산기 역할을 할 수 있도록 구현된 클래스 타입의 모델입니다.|

|Controller|역할|
|:---|:---|
|`JuiceViewController`|`JuiceMaker` 실행 시 보이는 `View`를 핸들링하는 `Controller` 입니다. 각 과일별 재고수량을 보여주고, 쥬스를 제조할 수 있는 버튼을 갖고 있습니다.|
|`FruitViewController`|쥬스를 만들 과일의 수량이 부족하거나 재고의 수정이 필요할 때 사용하는 `View`를 핸들링하는 `Controller` 입니다. 각 과일의 현재 재고수량을 확인하고, `Stepper`를 통해 그 수를 조정할 수 있습니다.|

---

## Step1 - 쥬스 메이커 타입 정의
[PR #26 | Step1 - 쥬스 메이커 타입 정의](https://github.com/tasty-code/ios-juice-maker/pull/26)

- Singleton Desing Pattern을 사용하여 과일의 재고를 관리하는 FruitStore 타입 정의
- ViewController의 request를 받아 주문서에 맞는 음료 제조를 역할을 하는 JuiceMaker 타입 정의

관리하는 과일의 종류로는 딸기, 바나나, 파인애플, 키위, 망고 총 5가지를 가지고 있으며 각 과일 종류마다
할당되는 초기 재고수량은 10개로 정의한다.
FruitStore 객체는 전체 재고 수량을 조절해야하기 때문에 ViewController에서 `재고 수정` 버튼으로
요청이 들어올 때 수량을 n개 변경하는 기능을 구현하였다.

JuiceMaker는 FruitStore를 소유하고 있어 공유자원을 통해 음료를 제조할 수 있으며
`startMake(single:)`과 `startMake(mix:)`를 통해 어떤 음료를 주문받는지 분기할 수 있으며
`requestTo(single:)`과 `requestTo(mix:)`를 통해 주문 받은 과일의 종류를 알려주면 하나의 메서드 안에서 제조할 수 있도록 하였습니다.
reqeust 메서드 안에는 주문 받았을 때 과일의 재고가 부족하면 기존 재고를 유지하고 제조할 수 없다는
메세지를 출력합니다.
    
### 🚀 적용해보려고 노력해본 점

#### 1. 프로토콜 채택
- Model/Protocol 내 채택할 프로토콜 파일 생성
- Makeable.swift, Computable.swift
```Swift
protocol Makeable {}
protocol Computable {}
```
JuiceMaker, Calculator에서 모든 코드를 작성/수정하는 것이 아니라 프로토콜을 사용함으로써 기능의 변동사항이 발생 시 반영을 쉽게 했습니다.
실제 Calculator는 처음에 add, subtract만 기능하였는데 compare 메서드가 필요했을 때 채택했던
Computable에 추가하여 바로 반영이 가능했습니다.
또한 이렇게 프로토콜을 채택하면서 각각이 필요한 기능만 하도록 제약하여 역할의 분리를 꾀할 수 있었습니다.

#### 2. 중복되는 코드 메서드화

JuiceMaker의 requestTo 메서드는 처음에 각 Single Fruit Juice, 각 Mix Fruit Juice에 있었습니다.
그러나 과일 유형만 다르고 코드가 동일했기 때문에 forEach를 사용하여 하나의 메서드로 통합할 수 있었습니다.

---
## Step2 - 초기화면 기능구현
[PR #40 | Step2 - 초기화면 기능구현](https://github.com/tasty-code/ios-juice-maker/pull/40)
- `재고 수정` 버튼을 통한 화면 전환을 present Modally로 구현
- `쥬스 주문` 버튼을 통한 재고 부족 Alert에서 `예` 선택 시 재고 수정 화면으로 전환 (위와 동일)
- 초기 화면의 View가 올라오면 과일 타입마다 10개씩 보이도록 Label 구현

재고 수정 화면 전환을 위해 Storyboard에서 `NavigationController`를 사용하여 
BarButtonItem의 `RightButton`을 통해 `Action Segue` 형식을 `Present Modally`방법을
사용해서 전환이 이루어지도록 하였다.

쥬스 주문 버튼을 통해 필요한 갯수만큼 소모되고 이후 Alert으로 쥬스가 나왔음을 표시한다.
재고가 더이상 쥬스를 제조할 수 없을만큼 존재하면 쥬스를 제조할 수 없다는 Alert을 표시하며
주문을 취소할지(`아니오` 버튼) 재고를 수정할지(`예` 버튼) 선택할 수 있도록 하였고 재고를 수정한다면
NavigationController에 사용했던 방식과 동일하게 작동하여 화면을 전환한다.
### 🚀 적용해보려고 노력해본 점
NavigationController에서 화면 전환을 어떤 방식으로 할지 총 5가지의 방법이 있다.
- Show
- ShowDetail
- Present
- Presetn Modally
- Custom
하나씩 연결해 보았을 때 제일 많이 사용되는 `Show` 방식을 채택하여 화면을 뒤로갈 수 있는 버튼이
자동생성되는것을 확인하였다. 그 다음 Step3에서 진행되는 방식을 확인했을 때 Modal 형식으로 되어있었고
하여 `Present Modally`를 선택하였고 이후 쥬스 주문 버튼에서 `예` 버튼을 사용하였을 때
Alert의 Present 방식을 Modally로 사용하여 동일한 화면전환을 이루게하였다.
```Swift
private func presentModally() {
        guard let fruitNavigationController = self.storyboard?.instantiateViewController(identifier: "FruitNavi") as? UINavigationController else { return }
        fruitNavigationController.modalPresentationStyle = UIModalPresentationStyle.fullScreen
        self.present(fruitNavigationController, animated: true, completion: nil)
    }
```


---
## Step3 - 재고 수정 기능구현
[PR #40 | Step3 - 재고 수정 기능구현](https://github.com/tasty-code/ios-juice-maker/pull/40)
- NavigationBar의 Title을 `재고 추가`로 구현하고 `BarButtonItem`으로 `닫기`버튼 구현
- Storyboard에서 Auto Layout을 사용하여 화면 배치
- Stepper를 이용하여 재고 수량을 조절할 수 있도록 구현

각각의 과일 이미지를 보여주는 `UILabel`과 재고수량을 보여주는 `UILabel`을 `Outlet Collection`으로, 스텝퍼는 하나의 `IBAction`으로 그룹화 하여 작업을 시작했다.
`Delegate`에 `FruitViewController`의 재고 label initialize를 진행하는 `syncFruitStocks` 메서드를 담아 화면 전환이 되었을 때 기존 재고가 표시되도록 하였다.
이후 `Stepper`로 증감한 수를 재고에 업데이트 할 수 있었다.

### 🚀 적용해보려고 노력해본 점
- Delegate (Jason)
ViewController간에 데이터를 전송하는 기본적인 방식으로 present 메서드와 Segue를 이용하여 전송하는 방법으로 진행해보려고 했다.
구현과정 중 실제로 재고수정 버튼을 푸쉬하였을 때 값이 잘 넘어갔었지만 Label의 레이아웃이 잡히지 않아서 값을 확인하는 과정에 오해가 있었고 이후 Delegate를 사용하여 잘풀어냈다.

- modalPresentationStyle (Jason)
화면 전환 시 NavigationController를 사용하여 화면 전환을 할 때와 마찬가지로 Alert을 이용하였을 때도 동일한 방법으로 전환되지 않았던 문제를 아래와 같은 코드로 구현하여 해결하였다.
(NavigationController를 사용할 때 present Modally 방식으로 Action Segue를 주었다.)
```swift
private func presentModally() {
        guard let fruitNavigationController = self.storyboard?.instantiateViewController(identifier: "FruitNavi") as? UINavigationController else { return }
        fruitNavigationController.modalPresentationStyle = UIModalPresentationStyle.fullScreen
        self.present(fruitNavigationController, animated: true, completion: nil)
    }
```


---

## Step1 실행화면
<img src="https://user-images.githubusercontent.com/92699723/210941422-16c25bf6-6bdb-4239-ae0b-39853c1697ea.png" width=500>

## Step2 실행화면
<img src="https://user-images.githubusercontent.com/45708630/212285108-37a684ff-2c32-450c-9594-95af4d4e33c5.png" width="360">

<img src="https://user-images.githubusercontent.com/45708630/212287312-fe4b15b5-f1eb-4eed-9167-54697b9396c4.png" width="360">

<img src="https://user-images.githubusercontent.com/45708630/212287423-e50cccac-9140-4886-979a-f9a9174853c3.png" width="360">

## Step3 실행화면
<img width="360" alt="image" src="https://user-images.githubusercontent.com/45708630/212287517-9f7c9235-beb9-4360-8893-5be8266be212.png">
<img width="360" alt="image" src="https://user-images.githubusercontent.com/45708630/212287656-23d80fbf-3ebc-4e1e-a222-7d04d87955a5.png">