# ๐งios-juice-maker
**[Step 1]** ์ฅฌ์ค ๋ฉ์ด์ปค ํ์
์ ์<br>
**[Step 2]** ์ด๊ธฐํ๋ฉด ๊ธฐ๋ฅ ๊ตฌํ<br>
**[Step 3]** ์ฌ๊ณ ์์ , ์๋ฆผ์ฐฝ ๊ธฐ๋ฅ ๋ฐ ๋ฐ์ดํฐ ์ ๋ฌ ๊ตฌํ<br>
<br>
## ๐ฒ ์คํ ํ๋ฉด

<br>
## ๐ ํด๋ ๊ตฌ์กฐ

<br>
## โ๏ธ ํ์
๋ณ ์ญํ ๋ถ๋ฐฐ
| struct | ์ญํ |
| --- | --- |
| `Fruit` | - ๊ณผ์ผ๋ค์ ์ด๋ฆ๊ณผ ์ฌ๊ณ ๋ฅผ ๋ด๊ณ ์๋ ๊ตฌ์กฐ์ฒด |
| `OrderMessage` | - ์ฃผ๋ฌธ๋ ๊ณผ์ผ ์ด๋ฆ๊ณผ ํ์ํ ์์ ๋ด๊ณ ์๋ ๊ตฌ์กฐ์ฒด |
| `JuiceMaker` | - ์ฃผ์ค๋ฅผ ๋ง๋๋ ํจ์๋ฅผ ๊ฐ์ง๊ณ ์๋ ๊ตฌ์กฐ์ฒด|
| class | ์ญํ |
| --- | --- |
| `FruitStore` | - fruits : ๊ณผ์ผ๋ค์ ์ฌ๊ณ ๋ฅผ ๋ด๋ ๋ณ์<br>- increaseStock(of: by:) : ๊ณผ์ผ ์ฌ๊ณ ๋ฅผ ๋ณ๊ฒฝ(์ฆ๊ฐ)ํ๋ ๋ฉ์๋<br>- dereaseStock(of: by:) : ๊ณผ์ผ ์ฌ๊ณ ๋ฅผ ๋ณ๊ฒฝ(๊ฐ์) ํ๋ ๋ฉ์๋<br>- checkStock(message:) : ๋ ์ํผ์์ ์๊ตฌํ๋ ์ฌ๋ฃ์ ์๋ณด๋ค ์ฌ๊ณ ๊ฐ ๋ง์์ง๋ฅผ ํ์ธํ๋ ๋ฉ์๋ |
|Label Class|์ค๋ช
|
| --- | --- |
|`{๊ณผ์ผ๋ช
}StockLabel`|{๊ณผ์ผ๋ช
}Label ์ ์|
|**Stepper Button class**|**์ค๋ช
**|
|`{๊ณผ์ผ๋ช
}Stepper`|{๊ณผ์ผ๋ช
}Stepper ๋ฒํผ ์ ์|
|**Order Button class**| **์ค๋ช
** |
|`{์ฅฌ์ค๋ช
}Button`|{์ฅฌ์ค๋ช
}Button ์ ์|
| enum | ์ญํ |
| --- | --- |
| `Errors` | - ์๋ฌ์ ์ |
| `Fruits` | - ๊ณผ์ผ ์ข
๋ฅ ์ ์<br>- 10๊ฐ์ฉ ๊ณผ์ผ ์ด๊ธฐํ ๋ฉ์๋ |
| `Juices` | - ๊ฐ ์ฅฌ์ค ์ด๋ฆ ์ ์<br>- ์ฅฌ์ค๋ค์ ๋ ์จํผ ์ ์ |
| `Messages` | - Alert์ ๋
ธ์ถ๋ ๋ฉ์ธ์ง ์ ์ |
| protocol | ์ญํ |
| --- | --- |
| `FruitStockManagable` | - ์ฌ๊ณ ๊ด๋ฆฌ์ ๊ด์ฌํ ์ ์๋ ๊ฐ์ฒด๋ค์ ์ค์์ฌํญ ์ ๊ณต |
| `JuiceOrderable` | - ์ ์ ์ ์ฃผ๋ฌธ์ ๋ฐ๋ ๊ฐ์ฒด๋ค์ ์ค์์ฌํญ ์ ๊ณต|
<br>
## [Step 1] ์ฅฌ์ค ๋ฉ์ด์ปค ํ์
์ ์
๐ [PR #21 | JuiceMaker [STEP 1] Logan, Blue](https://github.com/tasty-code/ios-juice-maker/pull/21)
### โ
๊ตฌํ ์๊ตฌ์ฌํญ
- FruitStore ํ์
์ ์
- ๊ด๋ฆฌํ๋ ๊ณผ์ผ: ๋ธ๊ธฐ, ๋ฐ๋๋, ํ์ธ์ ํ, ํค์, ๋ง๊ณ
- ๊ณผ์ผ์ ์ด๊ธฐ ์ฌ๊ณ : 10๊ฐ
- ๊ณผ์ผ ์๋๋ณ๊ฒฝ ๊ธฐ๋ฅ
- JuiceMaker ํ์
์ ์
- ๋ ์ํผ์ ๋ง์ถฐ ๊ณผ์ผ์ฃผ์ค ์ ์กฐ
- ๊ณผ์ผ์ ์ฌ๊ณ ๊ฐ ๋ถ์กฑํ๋ฉด ์ฅฌ์ค ์ ์กฐ ๋ถ๊ฐ
- FruitStore๋ฅผ ์์ ํ๊ณ ์์
### โ๏ธ ๊ณ ๋ฏผ ๋ฐ ํด๊ฒฐ
1. **`FruitStore`๋ ์ class๋ก ๊ตฌํ๋์ด ์์์๊น?**
๊ณผ์ ๋ฅผ ์ฒ์ ๋ฐ์์ ๋ย `class FruitStore {}`ย ํํ๋ก ๊ตฌํ์ด ๋์ด์๋ ๊ฒ์ ๋ณด๊ณ ย **singleton**์ผ๋ก๊ตฌํํ ๊ฒ์ ์๋ํ ๊ฒ์ด ์๋๊ฐ! ํ์ฌ ๊ตฌํํด ๋ณด๋ ค๊ณ ํ์์ต๋๋ค.`FruitStore`๋ฅผ singleton์ผ๋ก ์ฌ์ฉํ๊ณ ์ ํ ์ด์ ๋ ์๋์ ๊ฐ์ต๋๋ค.
- ๊ณผ์ผ ์ฌ๊ณ ์ ์ฅ์์ด๊ธฐ ๋๋ฌธ์ ๊ณผ์ผ์ฅฌ์ค๋ฅผ ๋ง๋ค ๋ ๊ณผ์ผ์ ๊ฐ์ ธ๋ค ์จ์ผ ํจ
- ๊ณผ์ผ์ ์ฌ๊ณ ๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ๊ฐ์์ํค๋ ๊ธฐ๋ฅ์ด ์์ด์ผ ํจ
- ์์ ๊ธฐ๋ฅ์ ์ํํ ๋ย `FruitStore`๊ฐ ์๋ย **์ธ๋ถ์์ ์ ๊ทผํ ๊ฐ๋ฅ์ฑ**์ด ์๊ณ , ํ ๊ณณ์์ ์ฌ๊ณ ๊ฐ๊ด๋ฆฌ๋์ด์ผ ํ๋ฏ๋ก,ย `singleton`์ผ๋ก ๊ตฌํํ ํ์์ฑ ๋๋
2. **`JuiceMaker`๋ ์ struct๋ก ๊ตฌํ๋์ด ์๋๊ฐ?**
์๋์ ๊ตฌ์กฐ์ฒด ์ฌ์ฉ case ์คย **๋ค๋ฅธ ํ์
์ผ๋ก๋ถํฐ ์์๋ฐ๊ฑฐ๋ ์์ ์ ์์ํ ํ์๊ฐ ์์ ๋**์ ํด๋นํ๋ค๊ณ ์๊ฐํ์ฌ struct๋ก ๊ตฌํ๋์ด ์๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ์๋ค.
- ์ ํ์ย [๊ฐ์ด๋๋ผ์ธ](https://developer.apple.com/documentation/swift/choosing-between-structures-and-classes)์์ ๋ค์ ์กฐ๊ฑด ์ค ํ๋ ์ด์์ ํด๋นํ๋ค๋ฉด ๊ตฌ์กฐ์ฒด๋ฅผ ์ฌ์ฉํ ๊ฒ์ ๊ถ์ฅํจ
- ์ฐ๊ด๋ ๊ฐ๋จํ ๊ฐ์ ์งํฉ์ ์บก์ํํ๋ ๊ฒ๋ง์ด ๋ชฉ์ ์ผ ๋
- ์บก์ํํ ๊ฐ์ ์ฐธ์กฐํ๋ ๊ฒ๋ณด๋ค ๋ณต์ฌํ๋ ๊ฒ์ด ํฉ๋นํ ๋
- ๊ตฌ์กฐ์ฒด์ ์ ์ฅ๋ ํ๋กํผํฐ๊ฐ ๊ฐ ํ์
์ด๋ฉฐ ์ฐธ์กฐํ๋ ๊ฒ๋ณด๋ค ๋ณต์ฌํ๋ ๊ฒ์ด ํฉ๋นํ ๋
- ๋ค๋ฅธ ํ์
์ผ๋ก๋ถํฐ ์์๋ฐ๊ฑฐ๋ ์์ ์ ์์ํ ํ์๊ฐ ์์ ๋
<br>
## [Step 2] ์ด๊ธฐํ๋ฉด ๊ธฐ๋ฅ ๊ตฌํ
๐ [PR #28 | JuiceMaker [STEP 2] Logan, Blue](https://github.com/tasty-code/ios-juice-maker/pull/28)
### โ
๊ตฌํ ์๊ตฌ์ฌํญ
- ์ฌ๊ณ ์์ ๋ฒํผ์ ์ฌ๊ณ ์ถ๊ฐ ํ๋ฉด์ผ๋ก ์ด๋ํ๋ ๊ธฐ๋ฅ ๊ตฌํ
- ์ฃผ๋ฌธ ๋ฒํผ ํฐ์น ์
- ์ฌ๊ณ ๊ฐ ์์ผ๋ฉด โ โ์ฅฌ์ค ๋์์ต๋๋ค! ๋ง์๊ฒ ๋์ธ์!โ ์ผ๋ฟ ํ์
- ์ฌ๊ณ ๊ฐ ์์ผ๋ฉด โ โ์ฌ๋ฃ๊ฐ ๋ชจ์๋ผ์. ์ฌ๊ณ ๋ฅผ ์์ ํ ๊น์?โ ์ผ๋ฟ ํ์
- ์ โ ์ฌ๊ณ ์์ ํ๋ฉด์ผ๋ก ์ด๋
- ์๋์ค โ ์ผ๋ฟ ๋ซ๊ธฐ
- ๊ณผ์ผ์ฅฌ์ค ์ ์กฐ์ ๋ฐ๋ฅธ ์ฌ๊ณ ๋ณ๊ฒฝ์ฌํญ ๋ฐ์
### โ๏ธ ๊ณ ๋ฏผ ๋ฐ ํด๊ฒฐ
1. **ํ๋ฉด ์ ํ ๋ฐฉ์์ผ๋ก ์ `Modal ๋ฐฉ์`์ ์ฌ์ฉํ์๋๊ฐ?**
- ๊ธฐ์กด์ ์ ์๋๋ ํํธ๊ฐ `EditStockViewController`๋ ๋ค๋น๊ฒ์ด์
๋ฐฉ์์ ์ฌ์ฉํ๋๋ก ์ค๊ณ๋์ด ์์์ต๋๋ค.
- ํ์ง๋ง Modal ๋ฐฉ์์ ์ฑํํ์๊ณ , ์ด์ ๋ ์๋์ ๊ฐ์ต๋๋ค.
- ***โ๋ชจ๋ฌ์ ๋ด๋น๊ฒ์ด์
์ธํฐํ์ด์ค ์๋ ๋ฌ๋ฆฌ ์ ๋ณด์ ํ๋ฆ์ด ์๋๋ผ ๋จ์ง ์ฌ์ฉ์๋ก๋ถํฐ ์
๋ ฅ์ ๋ฐ๊ธฐ์ํด ์ด๋ชฉ์ ๋๋ ๋ฐฉ์์ด๋ค.โ*** ๋ผ๋ ์ ์์ ์๊ฑฐํ์ฌ ์ฌ๊ณ ๋ฅผ ์์ ํ๋ ํ์๋ ์ฌ์ฉ์์ ๊ฐ๋จํ ์
๋ ฅ์ผ๋ก ์ด๋ค์ง๊ธฐ ๋๋ฌธ
- [Apple์ Human Interface Guideline](https://developer.apple.com/design/human-interface-guidelines/patterns/modality)์ ๋ฐ๋ฅด๋ฉด **โAim to keep modal tasks simple, short, and narrowly focused.โ** ์ ๋ช
์๋์ด ์๋ ๊ฒ์ฒ๋ผ โ์ฌ๊ณ ์์ โ์ ์์
์ ๋ฒ์๊ฐ ๋จ์ํ๊ณ ์ข์ ๋ฒ์์ ํธ์ง์ด๊ธฐ ๋๋ฌธ
- **โHelp people perform a distinct, narrowly scoped task without losing track of their previous contextโ,** ์ฌ์ฉ์๋ค์ด ์ด์ ์ปจํ
์คํธ๋ฅผ ์์ง ์๊ณ ๋ช
ํํ๊ณ ์ข์ ๋ฒ์์ ์์
์ ์ํํ์ฌ์ผ ํ๋ค๋ HIG์ ์ง์นจ์ ๋ฐ๋ผ, โ์ฌ๊ณ ์์ โ ์์
์ ์ด์ ํ๋ฉด์ ์ปจํ
์คํธ๋ฅผ ์์ง ์๊ณ ์์
์ด ์ํ๋์ด์ผํ๊ธฐ ๋๋ฌธ
<br>
## [Step 3] ์ฌ๊ณ ์์ ๋ฐ ๋ฐ์ดํฐ ์ ๋ฌ
๐ [PR #38 | JuiceMaker [STEP 3] Logan, Blue](https://github.com/tasty-code/ios-juice-maker/pull/38)
### โ
๊ตฌํ ์๊ตฌ์ฌํญ
- ํ๋ฉด ์ ๋ชฉ '์ฌ๊ณ ์ถ๊ฐ' ๋ฐ '๋ซ๊ธฐ' ๋ฒํผ ๊ตฌํ
- ๋ซ๊ธฐ ํฐ์น ์ ์ด์ ํ๋ฉด์ผ๋ก ๋ณต๊ท
- ์ฌ๊ณ ์ถ๊ฐ ํ๋ฉด ์ง์
์ ๊ณผ์ผ์ ํ์ฌ ์ฌ๊ณ ์๋ ํ์
- +, -๋ฅผ ํตํ ์ฌ๊ณ ์์
- iPhone12 ์ธ์ ๋ค๋ฅธ ์๋ฎฌ๋ ์ดํฐ์์๋ UI๊ฐ ์ ์์ ์ผ๋ก ๋ณด์ผ ์ ์๋๋ก ์คํ ๋ ์ด์์ ์ ์ฉ
### โ๏ธ ๊ณ ๋ฏผ ๋ฐ ํด๊ฒฐ
1. STEP2์์๋ label ๋ฐ stepper๋ฅผ ํ๋์ฉ Outlet์ผ๋ก ์ ์ธ ํ ์ฐ๊ฒฐํ์ฌ ์ฌ์ฉํ์์ต๋๋ค.
์ ์ธ๋ถ๊ฐ ๋ฐ๋ณต๋๋ ๋ฌธ์ ๋ฅผ ๊ฐ์ ํ๊ธฐ ์ํด `Outlet Collection`์ผ๋ก ๊ฐ์ ํด ๋ณด์์ต๋๋ค!
โช **ViewController.swift**์ ๊ธฐ์กด label ์ ์ธ๋ถ ์ฝ๋
```swift
@IBOutlet weak var strawberryLabel: UILabel!
@IBOutlet weak var bananaLabel: UILabel!
@IBOutlet weak var pineappleLabel: UILabel!
@IBOutlet weak var kiwiLabel: UILabel!
@IBOutlet weak var mangoLabel: UILabel!
```
โฉ **Outlet Collection**์ผ๋ก ์์
```swift
@IBOutlet var fruitStockLabels: [UILabel]!
```
2. `protocol`์ ์ด์ฉํ์ฌ ํด๋์ค๋ก ์ ์๋๊ณ Collection์ผ๋ก ์ฎ์ธ ๋ฒํผ๋ค์ ํ๋๋ก ๊ด๋ฆฌ ํด์ฃผ์์ต๋๋ค.
๐ **Protocols.swift**
```swift
protocol FruitStockManagable {
var fruitName: Fruits { get }
}
protocol JuiceOrderable {
var juice: Juices { get }
}
```
์์ ๋ `FruitStockManagable`, `JuiceOrderable`์ ๊ฐ ๋ฒํผ๋ค์ ์ ์ฒด์ฑ์ ํ์ธํ๋๋ฐ ๊ผญ ํ์ํ ์์๋ค์ ์๊ตฌ์ฌํญ์ผ๋ก ์ ์ํ๊ณ ์์ต๋๋ค.
๐ **FruitLabels.swift, FruitSteppers.swift, JuiceOrderButtons.swift**
```swift
// JuiceMakerVC์ ์ฌ๊ณ ๋ฅผ ๋ํ๋ด๋ ๋ผ๋ฒจ์ ํด๋์ค ์ ์์ค "๋ธ๊ธฐ"
class StrawberryStockLabel: UILabel, FruitStockManagable {
var fruitName: Fruits = .strawberry
// JuiceMakerVC์ ์ฃผ๋ฌธ ๋ฒํผ ์ค "๋ธ๊ธฐ๋ฐ๋๋์ฅฌ์ค"
class StrawberryJuiceButton: UIButton, JuiceOrderable {
var juice: Juices = .strawberry
}
// EditStockVC์ ์ฌ๊ณ ์์ ํ๋ ๋ฒํผ StepperButton์ ์ ์์ค ๋ธ๊ธฐ ๋ถ๋ถ
class StrawberryStepper: UIStepper, FruitStockManagable {
var fruitName: Fruits = .strawberry
}
}
```
4. Alert ๋์ฐ๋ ๋ฉ์๋๋ฅผ ํ๋๋ก ํตํฉํ์์ต๋๋ค.
- ๊ธฐ์กด์๋ ์ ํ์ง๊ฐ 1๊ฐ์ธ(์) ์๋ฆผ์ฐฝ๊ณผ ์ ํ์ง๊ฐ 2๊ฐ์ธ(์ / ์๋์ค) ์๋ฆผ์ฐฝ์ ๋๊ฐ ๋ฐ๋ก ์ ์ธํ์ฌ ๋์ํ์ง๋ง ๊ฐ์ ์์
์ ํ๋ ๋ฉ์๋๊ฐ 2๊ฐ์ธ๊ฒ์ด ๋ฐ๋์ง ํ์ง ์๋ค๊ณ ์๊ฐํ์ฌ ์ดํ ๋ฆฌํฉํ ๋ง ์์
์์ ํ๋๋ก ํตํฉํ์์ต๋๋ค.
๐ **ViewController.swift**
```swift
private func popAlert(with message: String?, error: Error?) {
if message != nil && error != nil { return }
if let message {
let alert = UIAlertController(title: message, message: nil, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "์", style: .default, handler: nil))
present(alert, animated: true)
}
if let error {
let alert = UIAlertController(title: error.localizedDescription, message: nil, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "์", style: .default, handler: {_ in
self.moveToEditStockView()}))
alert.addAction(UIAlertAction(title: "์๋์ค", style: .destructive, handler: nil))
present(alert, animated: true)
}
}
```
<br>
## ๐๏ธย ํ์ต ํค์๋
- string.index
- enum - rawValue์ ์ฌ์ฉ
- Singleton
- ์๋ฌ ํธ๋ค๋ง (`do-catch`, `try`)
- Navigation bar item
- Alert controller
- Modality
- Auto Layout
- Custom Class
- Outlet Collection
- Type Casting
- Stepper
<br>
## ๐ Team Bu-Lo ๐
๐๐ป๐๐ปโโ๏ธ๐จ **ํ๋ก์ ํธ ๊ธฐ๊ฐ:** `23.01.02` ~ `23.01.13`
|<img src="https://avatars.githubusercontent.com/u/71758542?v=4" width=200>|<img src="https://avatars.githubusercontent.com/u/29590768?v=4" width=200>|
|:---:|:---:|
|[๐ Blue ๐](https://github.com/bomyuniverse)|[๐ Logan ๐](https://github.com/sloDevz)|