# ๐น ์บ ํผ๋ค์ ๋ชฉ๋ง๋ฆ์ ์ฑ
์์ง๋ค! ์ฅฌ์ค ๋ฉ์ด์ปค
## ๐ ๋ชฉ์ฐจ
1. [ํ ์๊ฐ](#-ํ-์๊ฐ)
2. [๊ธฐ๋ฅ ์๊ฐ](#-๊ธฐ๋ฅ-์๊ฐ)
3. [Diagram](#-Diagram)
4. [ํด๋ ๊ตฌ์กฐ](#-ํด๋-๊ตฌ์กฐ)
5. [ํ์๋ผ์ธ](#-ํ์๋ผ์ธ)
6. [ํธ๋ฌ๋ธ ์ํ
](#-ํธ๋ฌ๋ธ-์ํ
)
7. [๊ธฐ์ ์ ๋์ ](#-๊ธฐ์ ์ -๋์ )
8. [์ฐธ๊ณ ๋งํฌ](#-์ฐธ๊ณ -๋งํฌ)
## ๐ฑ ํ ์๊ฐ
|[Wonbi](https://github.com/wonbi92)|[woong](https://github.com/iOS-Woong)|
|:---:|:---:|
| <img width="180px" img style="border: 2px solid lightgray; border-radius: 90px;-moz-border-radius: 90px;-khtml-border-radius: 90px;-webkit-border-radius: 90px;" src="https://avatars.githubusercontent.com/u/88074999?v=4">| <img width="180px" img style="border: 2px solid lightgray; border-radius: 90px;-moz-border-radius: 90px;-khtml-border-radius: 90px;-webkit-border-radius: 90px;" src="https://avatars.githubusercontent.com/u/96489602?v=4">|
- `Wonbi`์ `woong` ํ์ด ๋ง๋ ์ฅฌ์ค ๋ฉ์ด์ปค์
๋๋ค.
## โ๏ธ ๊ธฐ๋ฅ ์๊ฐ
|**์ฃผ์ค ์ฃผ๋ฌธํ๋ฉด**|**์ฌ๊ณ ์์ ํ๋ฉด**|
|:---:|:---:|
|||
|**์ฃผ๋ฌธ ์ฑ๊ณต(alert)**|**์ฃผ๋ฌธ ์คํจ(alert)**|
|||
|**์ฌ๊ณ ์์ ์ด๋(alert์ ํตํ ์ด๋)**|**์ฌ๊ณ ์์ ์ด๋(button์ ํตํ ์ด๋)**|
||
|
|**์ฌ๊ณ ์์ ์ ์ฉ(์ ์ฉ๋ฒํผ)**|**์ฌ๊ณ ์์ ์ทจ์(์ทจ์๋ฒํผ)**|
|||
## ๐ Diagram
### ๐งฌ Class Diagram

### ๐งฌ Flow Chart

## ๐ ํด๋ ๊ตฌ์กฐ
> Modal : ์ฑ ๊ตฌ๋ ๋ก์ง์ ํ์ํ ๋ชจ๋ธ
> View : ํ๋ฉด์ ๊ตฌ์ฑํ๋ ๋ทฐ
> Controller : ํ๋ฉด์ ์ด๋ฒคํธ์ ์ ํ์ ์ปจํธ๋กคํ๋ ์ปจํธ๋กค๋ฌ

## โฐ ํ์๋ผ์ธ
### ๐ Step 1
- class ํ์
์`FruitStore` ๊ตฌํ
- struct ํ์
์ `JuiceMaker`๊ตฌํ
- enum ํ์
์ `Juice`๊ตฌํ
- enum ํ์
์ `Fruit`๊ตฌํ
- error๋ฅผ ์ฑํํ enum ํ์
์ `StockError`๊ตฌํ
<details>
<summary>Details</summary>
<div markdown="1">
#### **220829**
- `Fruit`
- ํ์
์ผ์ด์ค ๊ตฌํ
- `FruitStore`
- ์ ์ฌ๊ณ ์ฒดํฌ ๋ฉ์๋ ๊ตฌํ
- ์ฌ๊ณ ๊ฐ์ ๋ณ๊ฒฝํ๋ ๋ฉ์๋,
ํจํด ๊ตฌํ
- `StockError`
- ์๋ฌ ์ผ์ด์ค ๊ตฌํ
#### **220830**
- `Juice`
- ํ์
์ผ์ด์ค ๊ตฌํ
- `FruitStore`
- `JuiceMaker`์๊ฒ ๊ณผ์ผ์ ์ ๋ฌํ๋ ๋ฉ์๋ ๊ตฌํ
- ๋ฉ์๋ ๋ก์ง ๋ณ๊ฒฝ ๋ฐ ์ปจ๋ฒค์
์์
- `JuiceMaker`
- ์ฃผ์ค ๋ง๋๋ ๋ฉ์๋ ๊ตฌํ
- ํ๋กํผํฐ ๊ธฐ๋ณธ๊ฐ ์ค์
- ์ปจ๋ฒค์
์์
#### **220831**
- ๋ฉ์๋ ๋ฐ ํ๋ผ๋ฏธํฐ๋ช
๋ฆฌํฉํ ๋ง
- ๋ฒ๊ทธ ์์
- `Fruit`
- ํ์
์ฌ์ ์
- `FruitStore`
- ์ฌ๊ณ ํ์ธํ๋ ๋ฉ์๋ ๋ก์ง ์์
- ์ฌ๊ณ ๋ฅผ ๋ณ๊ฒฝํ๋ ๋ฉ์๋ ๋ก์ง ์์
- ๊ณผ์ผ์ ์ ๋ฌํ๋ ๋ฉ์๋ ๋ก์ง ์์
#### **220901**
- ๋ฉ์๋ ๋ฐ ํ๋ผ๋ฏธํฐ๋ช
๋ฆฌํฉํ ๋ง
- `Fruit`
- ํ์
์ฌ์ ์
- `FruitStore`
- ์ฑ๊ธํค ์ญ์
- ์ฌ๊ณ ๋ฅผ ๋ณ๊ฒฝํ๋ ๋ฉ์๋ ๋ฆฌํฉํ ๋ง
- `JuiceMaker`
- ์ฅฌ์ค๋ฅผ ๋ง๋๋ ๋ฉ์๋ ๋ก์ง ์์
- `StockError`
- ์ญ์
#### **220902**
- ๋ฉ์๋ ๋ฐ ํ๋ผ๋ฏธํฐ๋ช
๋ฆฌํฉํ ๋ง
- `Recipe`
- ํ์
์ผ์ด์ค ๊ตฌํ
- `FruitStore`
- ์ด๋์
๋ผ์ด์ ๋ก์ง ์์
- ์ฌ๊ณ ๊ด๋ฆฌํ๋ ๋ฉ์๋ ๋ก์ง ์์
#### **220904**
- `Recipe`
- ์ญ์
- `Juice`
- ์ฌ๋ฃ์ ํ์๊ฐฏ์๋ฅผ ๋ํ๋ด๋ ํ๋กํผํฐ ์ถ๊ฐ
</div>
</details>
### ๐ Step 2
- `MainViewController` ์ด๋ฒคํธ์ ๋์ํ๋ ๋ก์ง ๊ตฌํ
- `EditViewController` ์์ฑ
- `EditView` ์คํ ๋ ์ด์์ ์ค์
- ๋ชจ๋ฌ ๋ฐฉ์์ ํ๋ฉด์ ํ ๊ตฌํ
<details>
<summary>Details</summary>
<div markdown="1">
#### **220905**
- ์ธ๊ทธ์จ์ด ๋ฐฉ์์ผ๋ก ํ๋ฉด ์ ํ๊ตฌํ
- `MainViewController`
- ๋ฒํผ ์ด๋ฒคํธ์ ๋์ํ๋ ๋ฉ์๋ ๊ตฌํ
- ๊ฒฐ๊ณผ์ ๋ง๋ Alert ๊ตฌํ
- ๋ทฐ์ ๋ ์ด๋ธ๊ณผ ๋ชจ๋ธ ๋ด๋ถ์ ์ฌ๊ณ ๊ฐ์ ์ฐ๊ฒฐ
- `EditViewController`
- ์์ฑ
- ์คํ ๋ ์ด์์ ์ค์
- ์ทจ์ ๋ฒํผ ๊ตฌํ
#### **220906**
- ์ฝ๋ ๋ค์ด๋ฐ ๋ฆฌํฉํ ๋ง
- ์ฝ๋๋ฅผ ํตํ ํ๋ฉด์ ํ ๋ฐฉ์์ผ๋ก ๋ฆฌํฉํ ๋ง
- `MainViewController`
- `NotificationCenter`๋ฅผ ํตํด ์ฌ๊ณ ๋ณ๊ฒฝ์๋ง๋ค ํ๋ฉด ๋ ์ด๋ธ์ ๋๊ธฐํ๋๋๋ก ๊ตฌํ
- ์ฃผ๋ฌธ ๋ฒํผ์ ์๋ณํ๋ ๋ก์ง ๊ตฌํ
#### **220907**
- `MainViewController`
- KVO๋ฅผ ํ์ฉํ์ฌ ์ฌ๊ณ ๋ฅผ ๋ํ๋ด๋ ๋ก์ง ๊ตฌํ
#### **220908**
- `MainViewController`
- KVO๋ฅผ ํตํด Alert์ ๋์ฐ๋๋ก ๋ฆฌํฉํ ๋ง
- ํ๋ฉด ์ ํ ์ ๋ฐ์ดํฐ ์ ๋ฌ์ ์ํ `StockStorage`ํ์
์ ์ฑ๊ธํค ํจํด์ผ๋ก ๊ตฌํ
- ์ฃผ๋ฌธ ๋ฒํผ์ ์๋ณํ๊ณ ์ฃผ๋ฌธ์ด ์ฑ๊ณตํ๋์ง ํ์ธํ๋ ๋ฉ์๋ ๊ธฐ๋ฅ๋ถ๋ฆฌ
#### **220912**
- ๋ค์ด๋ฐ ๋ฆฌํฉํ ๋ง, ์์คํ์ผ ์ ๋ฆฌ
- `MainViewController`
- KVO ์ ๊ฑฐ
- ๋ฉ์๋๋ฅผ ํตํด ๊ฐ์ ์ ๋ฌํ๋๋ก ๋ฆฌํฉํ ๋ง
</div>
</details>
### ๐ Step 3
- `EditViewController` ์ด๋ฒคํธ์ ๋์ํ๋ ๋ก์ง ๊ตฌํ
- `AlertMessage`๋ค์ ์คํ์ด์ค ๊ตฌํ
- Alert ๋ฉ์๋ ํ๋๋ก ํตํฉ
- ๊ฐ์ฒด ์บก์ํ
<details>
<summary>Details</summary>
<div markdown="1">
#### **220913**
- ์คํ ๋ ์ด์์ ์ ์ฉ
- `Response`
- ๋ค์ ์คํ์ด์ค enumํ์
๊ตฌํ
- `EditViewController`
- `Stepper`์ `value`๋ฅผ ์ค์ ํ๋ ๋ฉ์๋ ๊ตฌํ
- `Stepper` ์ด๋ฒคํธ์ ๋์ํ๋ ๋ก์ง ๊ตฌํ
- `FruitStore`
- ์ฌ๊ณ ๋ณ๊ฒฝํ๋ ๋ฉ์๋ ๋ก์ง ๋ฆฌํฉํ ๋ง
#### **220915**
- `AlertMessage`
- ํ์
๋ช
์ `Response`์์ `AlertMessage`๋ก ๊ต์ฒด
- Alert์ ๊ด๋ จ๋ ๋ชจ๋ ๋ฉ์์ง ์ถ๊ฐ
- `EditViewController`
- `Stepper` ์ด๋ฒคํธ์ ๋์ํ๋ ๋ก์ง ๋ฆฌํฉํ ๋ง
- Alert ๋ฉ์๋ ํ๋๋ก ํตํฉ
#### **220916**
- `EditViewController`
- ๋ด๋ถ ํ๋กํผํฐ `stock`์ `FruitStore` ๋ด๋ถ๋ก ์บก์ํ
</div>
</details>
## ๐๐ป ๊ธฐ์ ์ ๋์
[์ฑ๊ธํค](https://github.com/wonbi92/ios-juice-maker/wiki/%ED%8A%B8%EB%9F%AC%EB%B8%94-%EC%8A%88%ED%8C%85-&-%EA%B8%B0%EC%88%A0%EC%A0%81-%EB%8F%84%EC%A0%84#%EF%B8%8F-%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4)
[NotificationCenter](https://github.com/wonbi92/ios-juice-maker/wiki/%ED%8A%B8%EB%9F%AC%EB%B8%94-%EC%8A%88%ED%8C%85-&-%EA%B8%B0%EC%88%A0%EC%A0%81-%EB%8F%84%EC%A0%84#%EF%B8%8F-notificationcenter)
[KVOํจํด](https://github.com/wonbi92/ios-juice-maker/wiki/%ED%8A%B8%EB%9F%AC%EB%B8%94-%EC%8A%88%ED%8C%85-&-%EA%B8%B0%EC%88%A0%EC%A0%81-%EB%8F%84%EC%A0%84#%EF%B8%8F-kvo-%ED%8C%A8%ED%84%B4)
[Delegateํจํด](https://github.com/wonbi92/ios-juice-maker/wiki/%ED%8A%B8%EB%9F%AC%EB%B8%94-%EC%8A%88%ED%8C%85-&-%EA%B8%B0%EC%88%A0%EC%A0%81-%EB%8F%84%EC%A0%84#%EF%B8%8F-delegate-%ED%8C%A8%ED%84%B4)
## ๐ ํธ๋ฌ๋ธ ์ํ
[ํ๋ฉด ์ ํ์ ๋ฉ์๋๋ฅผ ํตํ ๋ฐ์ดํฐ ์ ๋ฌ](https://github.com/wonbi92/ios-juice-maker/wiki/%ED%8A%B8%EB%9F%AC%EB%B8%94-%EC%8A%88%ED%8C%85-&-%EA%B8%B0%EC%88%A0%EC%A0%81-%EB%8F%84%EC%A0%84#-%ED%99%94%EB%A9%B4-%EC%A0%84%ED%99%98%EC%8B%9C-%EB%A9%94%EC%84%9C%EB%93%9C%EB%A5%BC-%ED%86%B5%ED%95%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%84%EB%8B%AC)
[Alert ํจ์๋ฅผ ์ฌ๋ฌ๊ฐ๋ก ๋ถ๋ฆฌํ๋ ๊ฒ์ด ์๋ ํ๋์ ํจ์๋ก ํตํฉ ๊ด๋ฆฌ](https://github.com/wonbi92/ios-juice-maker/wiki/%ED%8A%B8%EB%9F%AC%EB%B8%94-%EC%8A%88%ED%8C%85-&-%EA%B8%B0%EC%88%A0%EC%A0%81-%EB%8F%84%EC%A0%84#-alert-%ED%95%A8%EC%88%98%EB%A5%BC-%EC%97%AC%EB%9F%AC%EA%B0%9C%EB%A1%9C-%EB%B6%84%EB%A6%AC%ED%95%98%EB%8A%94-%EA%B2%83%EC%9D%B4-%EC%95%84%EB%8B%8C-%ED%95%98%EB%82%98%EC%9D%98-%ED%95%A8%EC%88%98%EB%A1%9C-%ED%86%B5%ED%95%A9-%EA%B4%80%EB%A6%AC)
[FruitStore์ ์์์ฌ๊ณ ๋ฅผ ๊ตฌํํจ์ผ๋ก์จ ์บก์ํ](https://github.com/wonbi92/ios-juice-maker/wiki/%ED%8A%B8%EB%9F%AC%EB%B8%94-%EC%8A%88%ED%8C%85-&-%EA%B8%B0%EC%88%A0%EC%A0%81-%EB%8F%84%EC%A0%84#-fruitstore%EC%97%90-%EC%9E%84%EC%8B%9C%EC%9E%AC%EA%B3%A0%EB%A5%BC-%EA%B5%AC%ED%98%84%ED%95%A8%EC%9C%BC%EB%A1%9C%EC%8D%A8-%EC%BA%A1%EC%8A%90%ED%99%94)
[rawValue์ ์ฌ์ฉ](https://github.com/wonbi92/ios-juice-maker/wiki/%ED%8A%B8%EB%9F%AC%EB%B8%94-%EC%8A%88%ED%8C%85-&-%EA%B8%B0%EC%88%A0%EC%A0%81-%EB%8F%84%EC%A0%84#-rawvalue%EC%9D%98-%EC%82%AC%EC%9A%A9)
## ๐ ์ฐธ๊ณ ๋งํฌ
[Swift API Design Guidelines - Naming](https://swift.org/documentation/api-design-guidelines/)
[Swift Language Guide - Initialization](https://docs.swift.org/swift-book/LanguageGuide/Initialization.html)
[Swift Language Guide - Access Control](https://docs.swift.org/swift-book/LanguageGuide/AccessControl.html)
[Swift Language Guide - Nested Types](https://docs.swift.org/swift-book/LanguageGuide/NestedTypes.html)
[Swift Language Guide - Type Casting](https://docs.swift.org/swift-book/LanguageGuide/TypeCasting.html)
[Swift Language Guide - Error Handling](https://docs.swift.org/swift-book/LanguageGuide/ErrorHandling.html)
---
[๐ ๋งจ ์๋ก ์ด๋ํ๊ธฐ](#-์ฅฌ์ค-๋ฉ์ด์ปค)
1. ์ฑ๊ธํค
2. NotificationCenter
3. KVO
4. Delegate
5. Data Send From Method
6. ์บก์ํ?
### ์ฑ๊ธํค ํจํด์ ํ์ฉ
```swift
class FruitStore {
static var stockManager = FruitStore()
var stock: [Fruit: Int] = Fruit.defaultStock
private init() {}
}
struct JuiceMaker {
let stockManager = FruitStore.stockManager
func requestFruit() -> Int {
let numberOfFruits = stockManager.stock[.strawberry]
return numberOfFruits
}
}
```
์ฒ์์ ๊ณผ์ผ์ ์ ์ฅํ๊ณ ์๋ FruitStore ํด๋์ค์ ์ฒ๋ฆฌ๋ฅผ `์ฑ๊ธํคํจํด`์ ํ์ฉํ์ฌ ๊ณผ์ผ์ ์๋์ ์ ์ฅํ๊ณ ์๋ ๋ฐฐ์ด ์ธ์คํด์ค๋ฅผ ๋ชจ๋ ๋ทฐ์ปจํธ๋กค๋ฌ ํน์ ๋ชจ๋ธ์์ ํธ๋ฆฌํ๊ฒ ์ ๊ทผ ๊ฐ๋ฅํ๋๋ก ๊ตฌํ ํ๋ ค๊ณ ํ์์ต๋๋ค.
ํ์ง๋ง, ์ฑ๊ธํค ์ธ์คํด์ค์ ๋๋ฌด ๋ง์ ๋ฐ์ดํฐ๊ฐ ์ฐ๊ฒฐ๋ ๊ฒฝ์ฐ์ ๋ค๋ฅธ ํด๋์ค์ ์ธ์คํด์ค ๊ฐ ๊ฒฐํฉ๋๊ฐ ๋์์ง ๊ฒ์ ์ฐ๋ คํ๊ณ ,
์ฌ๋ฌ๊ตฐ๋ฐ์์ ์ฑ๊ธํค ๊ฐ์ฒด๋ฅผ ์ ๊ทผํ์ฌ ๊ฐ์ ๋ฐ๊พธ๊ฒ ๋ ๊ฒฝ์ฐ ์๋ํ์ง ์์ ๊ฒฐ๊ณผ๊ฐ ๋์ฌ ๊ฒ์ด๋ฏ๋ก
์ด ๋ฐฉ๋ฒ์ ์ฑํํ์ง ์๊ณ , FruitStore์ ๋ฐ์ดํฐ๊ฐ ํ์ํ ๊ฒฝ์ฐ, ๊ฐ ํ์
๋ด์์private์ผ๋ก FruitStore๋ฅผ ์์ฑํ์ต๋๋ค. ๋ฐ๋ผ์, ์ ์ญ ์ ๊ทผ์ ์ฐจ๋จํ์ฌ ์์ ํ๊ฒ ๊ด๋ฆฌํ์์ต๋๋ค.
### NotificationCenter
```swift
// MainViewController
private func settingObserver() {
NotificationCenter.default.addObserver(self,
selector: #selector(updateStockCount(_:)),
name: .changedStockCount,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(madeJuiceAlert(_:)),
name: .madeJuiceAlert,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(failedAlert(_:)),
name: .failedAlert,
object: nil)
}
// JuiceMaker
func makeJuice(_ juice: Juice) {
if store.canSupplyRequest(ingredient: juice.ingredient) {
NotificationCenter.default.post(name: .madeJuiceAlert,
object: nil,
userInfo: ["JuiceName" : juice.name])
} else {
NotificationCenter.default.post(name: .failedAlert,
object: nil)
}
}
}
// FruitStore
private(set) var stock: [Int] {
didSet {
NotificationCenter.default.post(name: .changedStockCount,
object: nil,
userInfo: nil)
}
}
```
- ์ฌ๊ณ ๊ฐ ์์ ๋ ๋๋ง๋ค ์์ ๋ ์ฌ๊ณ ๋ฅผ ํ๋ฉด์ ์
๋ฐ์ดํธ ํด์ฃผ๋ ๋ก์ง๊ณผ ์ฅฌ์ค ์ ์กฐ์ ์ฑ๊ณต ์คํจ์ฌ๋ถ๋ฅผ ์๋ ค์ฃผ๋ ๋ก์ง์ `NotificationCenter`๋ฅผ ํตํด ๊ตฌํํด ๋ณด์์ต๋๋ค.
- `NotificationCenter`์ ์ฅ์ ์ ์ฝ๋๊ฐ ์ํ๋ ์์ ์ ์ต์ ๋ฒ๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ์๋ฆผ์ ๋ฐ์กํ ์ ์๋ค๋ ์ ์ด๋ผ ์๊ฐํ์ต๋๋ค. ๋ํ, ๋ค๋ฅธ ํ์
์ ์ธ์คํด์ค๋ ํ๋กํผํฐ์ ์ ๊ทผํ์ง ์๊ณ ์์ ํ ๋ถ๋ฆฌ๋ ์ํ์์๋ ํฌ์คํ
๋ ์ ๋ณด๋ค์ ์ต์ ๋ฒ๋ฅผ ํตํด ๋ฐ์๋ผ ์ ์๋ ์ ์ด ์ฅ์ ์ด๋ผ ์๊ฐํ์ต๋๋ค.
- ํ์ง๋ง, `NotificationCenter`๋ ๋ฐ๋ก ์ค์ ํ์ง ์๋์ด์ ์ฑ ๋ด์ ๋ชจ๋ ๋ถ๋ถ์ post๋ฅผ ๋ ๋ฆฌ๋ ๋ก์ง์ผ๋ก ๊ตฌํ๋์ด์๊ณ , ์ฌ์ง์ด ๋ค๋ฅธ ๋ชจ๋์๋ post๊ฐ ๋๊ธฐ ๋๋ฌธ์, ์ฑ์ ์ํ๋ณํ๋ฅผ ์ฑ ์ ์ฒด ํน์, ๋ค๋ฅธ ์ฑ์ "์๋ฆฌ๋" ๊ฐ์ฒด๋ผ๋ ์๊ฐ์ด ๋ค์์ต๋๋ค.
- ์๋ฅผ ๋ค์ด, ํธ๋ํฐ์ ์ฌ์ฉํ๋ ์ค์ ์ ํ๊ฐ ์ค๋ฉด, `NotificationCenter`๋ฅผ ํตํด ์ ํ๊ฐ ์์ ๋์๋ค๋ ์ฌ์ค์ ์๋ฆฌ๊ณ , ๊ทธ์ ๋ง๊ฒ ์ฌ์ฉ์ค์ธ ์ฑ์ด ์ผ์์ ์ง๋๋๋ก ํ๋ ๋ฐฉ์์ผ๋ก ์ฌ์ฉ๋๋ ๊ฒ์ด ์ฌ๋ฐ๋ฅธ ์ฌ์ฉ๋ฐฉ๋ฒ์ด๋ผ ์๊ฐํ์ต๋๋ค.
- ์ด๋ฌํ ์ด์ ๋๋ฌธ์ `NotificationCenter`๋ ์ต์ข
์ ์ผ๋ก ์ฑํํ์ง ์๊ฒ ๋์์ต๋๋ค.
### KVO
```swift
// FruitStore
class FruitStore: NSObject {
@objc dynamic private(set) var stock: [Int]
}
// MainViewController
class MainViewController: UIViewController {
@objc let store = FruitStore(stockCount: 10)
override func viewDidLoad() {
super.viewDidLoad()
stockChangeObserver = observe(\.store.stock,
options: [.new, .initial],
changeHandler: { (object, stock) in
guard let newStock = stock.newValue else { return }
self.updateStockCount(stock: newStock)
})
}
}
```
- ๋ ๋ค๋ฅธ ๋ฐ์ดํฐ์ ๋ณํ๋ฅผ ์ฒดํฌํ๋ ๋ฐฉ๋ฒ์ธ KVO ํจํด์ ํตํด ์ฌ๊ณ ๊ฐ ์์ ๋ ๋ ๋ง๋ค ์์ ๋ ์ฌ๊ณ ๋ฅผ ํ๋ฉด์ ์
๋ฐ์ดํธ ํด์ฃผ๋ ๋ก์ง์ ๊ตฌํํด ๋ณด์์ต๋๋ค.
- KVO์ ์ฅ์ ์ ๋ ๊ฐ์ฒด๊ฐ ์ ๋ณด๋ฅผ ๋๊ธฐํ ํ๋๊ฒ์ด ๋งค์ฐ ์ฝ๋ค๋ ๊ฒ ์์์ต๋๋ค.
- ํ์ง๋ง, ๋ฐ๋์ ๊ทธ ๊ฐ์ฒด์ ์ธ์คํด์ค๋ฅผ ๊ฐ์ง๊ณ ์์ด์ผ๋ง ๋ฐ์ดํฐ์ ์ถ์ ์ด ๊ฐ๋ฅํ๋ค๋ ๋จ์ ์ด ์์๊ณ `NSObject`๋ฅผ ์์ ๋ฐ์ Objective-C ๋ฐํ์์ ์ด์ฉํด ๊ฐ์ ์ถ์ ํ๊ธฐ์ ๊ฐ๋จํ ๊ฐ ๋ณํ๋ฅผ ์ํด ์ด๋ ๊ฒ๊น์ง ๋ง์ ๋ฆฌ์์ค๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋ํ ์๋ฌธ์ด ์๊ฒผ์ต๋๋ค.
- ๊ฒ๋ค๊ฐ KVO์ ์ฅ์ ์ผ๋ก ๋ง์ด๋ค ๊ฑฐ๋ก ํ๋ `Nasted Type`์ ๊ฐ ๋ณํ๋ ์ถ์ ์ด ๊ฐ๋ฅํ๋ค๋ ์ ๋ ์ ํฌ์ ์ฑ์์๋ ๊ตณ์ด ์ฅ์ ์ผ๋ก ์์ฉํ์ง ์์์ต๋๋ค.
- ๊ฒฐ๋ก ์ ์ผ๋ก, ๊ฐ๋จํ ๊ฐ ๋ณํ๋ฅผ ์ต์ ๋น ํ๊ธฐ์ํด ๋ง์ ์ฝ๋์ค๊ณผ ๋ฆฌ์์ค๋ฅผ ์ฌ์ฉํ๋ค ํ๋จ๋์ด ์ฑํํ์ง ์์๊ณ , ๊ฐ์ด ๋ณํํ๋ ๊ฒฝ์ฐ์ ์ฌ๊ณ ๋ฅผ ํ๋ฉด์ ์
๋ฐ์ดํธ ํ๋ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ๋ฐฉ์์ผ๋ก ๊ตฌํํ๊ฒ ๋์์ต๋๋ค.
### Delegateํจํด
```swift
//editViewController - ์ฑํ ๋ฐ ์๊ตฌ๋ฉ์๋ ๊ตฌํ
extension EditViewController: SendDataDelegate {
func sendStock(_ stock: [Int]) {
self.stock = stock
}
}
//ViewController - ํ๋กํ ์ฝ ์ ์ธ ๋ฐ ํ๋กํผํฐ ์์ฑ
protocol SendDataDelegate: AnyObject {
func sendStock(_ stock: [Int])
}
class MainViewController: UIViewController {
weak var delegate: SendDataDelegate?
@IBAction private func tappedModifyBarButton(_ sender: Any) {
// EditViewController๋ฅผ ์ธ์คํด์คํ ํจ.
delegate = editViewController
delegate?.sendStock(store.stock)
present(editViewController, animated: true)
}
}
```
์ต์ด์ ์ค๊ณ์์ ๋ทฐ์ปจํธ๋กค๋ฌ ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๋ ๋ฐฉ์์ผ๋ก ์ง์ ํด๋น ํ๋กํผํฐ์ ์ ๊ทผํด data๋ฅผ ์ ๋ฌํ๋ ๋ฐฉ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ์ต๋๋ค.
ํ์ง๋ง, ๋ค๋ฅธ ๋ทฐ ์ปจํธ๋กค๋ฌ์ ํ๋กํผํฐ์ ์ง์ ์ ๊ทผํ๊ณ ํด๋น ์ปจํธ๋กค๋ฌ์ ์์กดํ๊ณ ์๋ ํํ์๊ณผ
๋์์ ํ๋กํผํฐ์ ์ง์ ์ ๊ทผ์ํ๊ฑฐ๋ ์ง์ ๊ฐ์ ์ค์ ํ๊ธฐ์ ๊ฒฐํฉ๋๊ฐ ๋์์ง๋ค๊ณ ํ๋จํ๊ณ ,
์ ์ฌํญ์ด ์ฐ๋ ค๋์ด `Delegate`๋ฅผ ์ด์ฉํ์ฌ ๊ฐ ๋ทฐ์ปจํธ๋กค๋ฌ ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ๋๋ก ์์ ํ์์ต๋๋ค.
ํ์ง๋ง, ๊ฐ๋จํ ๋ฐ์ดํฐ๋ง ์ ์กํ๋ ๋ก์ง์ `Delegate`๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ฌด ๋ง์ ์ฝ๋๋ฅผ ์์ฑํ๊ฒ ๋๋ค๋ ๋จ์ ์ด ์์๊ณ ์ฝ๋์ ๊ฐ๋
์ฑ์ ๋ง์ด ํด์น๋ค ํ๋จํ์ฌ ์ต์ข
์ ์ผ๋ก๋ ์ฑํํ์ง ์์๊ณ ๋ฐ์ดํฐ๋ฅผ ๋ฉ์๋๋ฅผ ํตํด ์ฃผ๊ณ ๋ฐ๊ฒ ํ์์ต๋๋ค.
### ํ๋ฉด ์ ํ์ ๋ฉ์๋๋ฅผ ํตํ ๋ฐ์ดํฐ ์ ๋ฌ
```swift
// MainViewController
class MainViewController: UIViewController {
private let store = FruitStore(stockCount: 10)
private lazy var juiceMaker = JuiceMaker(store: store)
@IBAction private func tappedModifyBarButton(_ sender: Any) {
// EditViewController๋ฅผ ์ธ์คํด์คํ ํจ.
editViewController.setStore(from: store)
present(editViewController, animated: true)
}
}
// EditViewController
class EditViewController: UIViewController {
private var store: FruitStore?
func setStore(from store: FruitStore) {
self.store = store
}
}
```
- ์ด๋ฒ ํ๋ก์ ํธ์ ํต์ฌ ํค์๋๋ผ๋ ์๊ฐ์ด ๋ค์์ต๋๋ค. ํ๋ฉด ์ ํ์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๋ ์ฌ๋ฌ๊ฐ์ง ๋ฐฉ๋ฒ์ ๋ํด ๊ณต๋ถํ์๊ณ ๊ทธ์ค์ ์ ํฌ๊ฐ ์ต์ข
์ ์ผ๋ก ์ฑํํ ๋ฐฉ๋ฒ์ "๋ฉ์๋๋ฅผ ํตํ ๋ฐ์ดํฐ ์ ๋ฌ"๋ฐฉ์ ์ด์์ต๋๋ค.
- ๋ค๋ฅธ ์ฌ๋ฌ๊ฐ์ง ๋ฐฉ๋ฒ๋ค ์ญ์ ์ฅ๋จ์ ์ด ์์์ง๋ง, ๊ฐ๋ฒผ์ด ๋ฐ์ดํฐ ํ๋๋ฅผ ๋๊ธฐ๊ธฐ ์ํด ์ฝ๋๊ฐ ๋๋ฌด ๊ธธ์ด์ง๊ธฐ๋ ํ๊ณ , ์ฌ์ฉ์ ์ฅ์ ๋ณด๋ค๋ ๋จ์ ์ด ๋ ๋ถ๊ฐ๋๋๊ฑฐ ๊ฐ์ ๊ฐ์ฅ ๊ฐ๋จํ๋ฉด์๋ ํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ ์ฑํํ๊ฒ ๋์์ต๋๋ค.
- `FruitStore`๋ `class`์ด๊ธฐ ๋๋ฌธ์, ์ฐธ์กฐ ํ์
์
๋๋ค. ๋ฐ๋ผ์ `MainViewController`์์ `EditViewController`๋ฅผ `present`ํ๊ธฐ ์ ์ `EditViewController`์ ํ๋กํผํฐ `store`๊ฐ `MainViewController`์ `store`๋ฅผ ์ฐธ์กฐํ๋๋ก ํ์์ต๋๋ค.
- ์ด ๊ฒฐ๊ณผ ์ฑ์๋ ์ฌ์ ํ ํ๋์ `store`๋ง ์กด์ฌํ๊ฒ ๋์ด ๊ฐ ์ปจํธ๋กค๋ฌ๊ฐ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๊ณ , ์ฌ๊ณ ์ ๋ฌด๊ฒฐ์ฑ์ ์ง์ผฐ์ผ๋ฉฐ, ๋์๊ฐ ์ฌ๊ณ ์ ๋ณ๊ฒฝ์ ๋ฐ๋ฅธ ๋ทฐ์ ๋ณํ๋ ๊ฐ๋จํ ์ฝ๋๋ก ๊ตฌํ์ด ๊ฐ๋ฅํด์ก์ต๋๋ค.
### FruitStore์ ์์์ฌ๊ณ ๋ฅผ ๊ตฌํํจ์ผ๋ก์จ ์บก์ํ
```swift
// FruitStore
class FruitStore {
private(set) var stock: [Int]
private(set) var queuedStock = [Int]()
func setQueuedStock() {
queuedStock = stock
}
func changeQueueStock(fruitIndex: Int, count: Int) {
queuedStock[fruitIndex] = count
}
func confirmChange() {
stock = queuedStock
queuedStock = [Int]()
}
}
// EditViewController
class EditViewController: UIViewController {
private var store: FruitStore?
@IBAction private func tappedCancelButton(_ sender: UIBarButtonItem) {
dismiss(animated: true)
}
@IBAction private func tappedApplyButton(_ sender: UIButton) {
store?.confirmChange()
dismiss(animated: true)
}
@IBAction private func tappedStepper(_ sender: UIStepper) {
let fruitIndex = sender.tag, newCount = sender.value
fruitCountLabels?[fruitIndex].text = Int(newCount).description
store?.changeQueueStock(fruitIndex: fruitIndex, count: Int(newCount))
}
```
- ๊ธฐ์กด ์ฝ๋์์๋ `EditViewController`์์ ์์ ์ฌ๊ณ ๋ฅผ ๊ฐ์ง๊ณ ์๊ณ , ๊ทธ ์ฌ๊ณ ๋ฅผ '์ ์ฉ' ๋ฒํผ์ ๋๋ ์ ๋ ์ฐธ์กฐํ๊ณ ์๋ ์ฌ๊ณ ์ ์ ์ฉํ๋๋ก ๊ตฌํํ์์ต๋๋ค.
- ํ์ง๋ง, `EditViewController`๊ฐ ์์ ์ฌ๊ณ ๋ฅผ ๊ฐ์ง๊ณ ์๋ ๊ฒ์ด ๊ฐ์ฒด์งํฅ์ "์บก์ํ"์ ์ ํฉํ์ง ์์ ๋ฐฉ๋ฒ์ด๋ผ๋ ์๊ฐ์ด ๋ค์ด์ ์ด๋ฅผ `FruitStore`์์ ์ง์ ์ฒ๋ฆฌํ๋๋ก ๋ฆฌํฉํ ๋ง์ ์งํํด ๋ณด์์ต๋๋ค.
- ์ด ์ญ์ ๋ฉ์๋๋ฅผ ํตํด์๋ง ๊ฐ์ด ๋ณ๊ฒฝ๋๋๋ก ํ์ฌ ๊ฒฐํฉ๋๋ฅผ ๋์ด์ง ์์ผ๋ฉด์ ๊ฐ์ด ๋ฐ๋๋๋ก ๊ตฌํํ์์ต๋๋ค.
### rawValue์ ์ฌ์ฉ
```swift
enum Juice: String {
case strawberryJuice = "๋ธ๊ธฐ ์ฃผ์ค"
case bananaJuice = "๋ฐ๋๋ ์ฃผ์ค"
case kiwiJuice = "ํค์ ์ฃผ์ค"
case pineappleJuice = "ํ์ธ์ ํ ์ฃผ์ค"
case mangoJuice = "๋ง๊ณ ์ฃผ์ค"
case strawberryBananaJuice = "๋ธ๋ฐ ์ฃผ์ค"
case mangoKiwiJuice = "๋งํค ์ฃผ์ค"
var name: String {
switch self {
case .strawberryJuice:
return "๋ธ๊ธฐ ์ฃผ์ค"
case .bananaJuice:
return "๋ฐ๋๋ ์ฃผ์ค"
case .kiwiJuice:
return "ํค์ ์ฃผ์ค"
case .pineappleJuice:
return "ํ์ธ์ ํ ์ฃผ์ค"
case .mangoJuice:
return "๋ง๊ณ ์ฃผ์ค"
case .strawberryBananaJuice:
return "๋ธ๋ฐ ์ฃผ์ค"
case .mangoKiwiJuice:
return "๋งํค ์ฃผ์ค"
}
}
}
```
- `enum`ํ์
์ `rawValue`์ฌ์ฉ์ ๋งค์ฐ ์ ์ฉํฉ๋๋ค. ํ์ง๋ง ์ด `rawValue`๋ผ๋ ๋งค์ง ๋ฆฌํฐ๋ด์ ๋ฐ๋ก ์ฌ์ฉํ๋ ๊ฒ์ ์ฝ๋์ ๊ฐ๋
์ฑ์ ๋จ์ด๋จ๋ฆฐ๋ค๋ ์๊ฐ์ด ๋ค์์ต๋๋ค.
- ๊ทธ๋์ ์ฒ์์๋ ์ฐ์ฐ ํ๋กํผํฐ๋ฅผ ์ด์ฉํด `switch`๋ฌธ์ผ๋ก `rawValue`๋ฅผ ํ์ฉํ๋ ํ๋กํผํฐ๋ฅผ ๋ง๋ค๊ฒ ๋์๋๋ฐ, ๋งค์ง ๋ฆฌํฐ๋ด์ ์ฌ์ฉํ์ง ์๊ฒ ๋์ด ์ฝ๋์ ๊ฐ๋
์ฑ์ ์ฌ๋ ค์ฃผ๊ธด ํ์ง๋ง, ์ฝ๋๊ฐ ๋๋ฌด ๊ธธ์ด์ง๋ ๋จ์ ์ด ์์์ต๋๋ค.
```swift
enum Juice: String {
case strawberryJuice = "๋ธ๊ธฐ ์ฃผ์ค"
case bananaJuice = "๋ฐ๋๋ ์ฃผ์ค"
case kiwiJuice = "ํค์ ์ฃผ์ค"
case pineappleJuice = "ํ์ธ์ ํ ์ฃผ์ค"
case mangoJuice = "๋ง๊ณ ์ฃผ์ค"
case strawberryBananaJuice = "๋ธ๋ฐ ์ฃผ์ค"
case mangoKiwiJuice = "๋งํค ์ฃผ์ค"
var name: String {
self.rawValue
}
}
```
- ๊ทธ๋ฆฌ๊ณ ํผ๋๋ฐฑ์ ํตํด ๋ค์๊ณผ ๊ฐ์ด ์์ ํ๊ฒ ๋์์ต๋๋ค. ๋๋ฌด.. ์๋ฆ๋ต์ต๋๋ค...โจโจ ์ด๋ฐ ์์ง๋ง ๊ธฐ๋ฐํ ์์ด๋์ด๊ฐ ์ฝ๋๋ฅผ ๋ ์คํํ๊ฒ ์์ฑํ ์ ์๋ค๋ ์ ์ ์๊ฒ ๋์์ต๋๋ค.
### Alert ํจ์๋ฅผ ์ฌ๋ฌ๊ฐ๋ก ๋ถ๋ฆฌํ๋ ๊ฒ์ด ์๋ ํ๋์ ํจ์๋ก ๊ตฌํ
```swift
private func resultAlert(isSuccess: Bool, juiceName: String = "") {
let alert = UIAlertController(title: nil,
message: isSuccess ? juiceName + AlertMesaage.successMesaage : AlertMesaage.failureMesaage,
preferredStyle: .alert)
let comfirmAction = UIAlertAction(title: isSuccess ? AlertMesaage.successConfirm : AlertMesaage.failureConfirm,
style: .default,
handler: isSuccess ? nil : { _ in self.tappedModifyBarButton(()) })
alert.addAction(comfirmAction)
if !isSuccess {
let noAction = UIAlertAction(title: AlertMesaage.failureCencel, style: .cancel)
alert.addAction(noAction)
}
present(alert, animated: true)
}
```
- ๊ธฐ์กด์๋ `์คํจ๊ฒฝ์ฐ์ Alert` & `์ฑ๊ณต๊ฒฝ์ฐ Alert`์ ๋ฉ์๋๋ก 2๊ฐ๋ก ๋ถ๋ฆฌํ์ฌ ๊ฐ๊ฐ ๊ตฌํํ์ฌ ์กฐ๊ฑด์ ๋ฐ๋ผ ๋ณ๊ฐ์ ๋ฉ์๋๊ฐ ์คํ๋๋๋ก ํ์์ต๋๋ค.
- ํ์ง๋ง, ์ฝ๋์ ๊ฐ๊ฒฐ์ฑ์ ์ํด ๋ก์ง๊ตฌํ๋ถ์์ Bool ํ์
์ ์ ๋ฌ์ธ์๋ก ๋ฐ์ ์คํจ ํ ๊ฒฝ์ฐ์ UIAlertController์ noAction ๋ณ์๊ฐ ์ถ๊ฐ๋๋๋ก ๊ตฌํํ์์ต๋๋ค.