- ์๊ฐ
- ํ์
- ํ์๋ผ์ธ
- ์๊ฐํ๋ ํ๋ก์ ํธ ๊ตฌ์กฐ
- ์คํ ํ๋ฉด
- ํธ๋ฌ๋ธ ์ํ
- ํต์ฌ ๊ฒฝํ
- ์ฐธ๊ณ ๋งํฌ
์ฌ์ฉ์์ ์ฃผ๋ฌธ์ ๋ฐ๋ฅธ ๐ง๊ณผ์ผ์ฅฌ์ค ๋ง๋ค๊ธฐ ์ฑ์ ๋๋ค! ์ค์๊ฐ ๊ณผ์ผ ์ฌ๊ณ ๋ฅผ ํ์ธํ ์ ์๊ณ , ๊ณผ์ผ์ ์ฌ๊ณ ์์ ๋ ๊ฐ๋ฅํฉ๋๋ค!
![image]()
์ ์ข | zhilly | bella |
---|---|---|
![]() |
![]() |
![]() |
@jonghancha | @zhilly11 | @hyhy0429 |
[STEP-1]
- 220829: Ground Rule ์์ฑ, STEP-1 Flow Chart ์์ฑ
- 220830: FruitStore, JuiceMaker ๋ชจ๋ธํ์ผ ์์ฑ
- FruitStore: ์ฌ๊ณ ๋ณ์, ์ฌ๊ณ ์ ์ ๊ทผ, ์ฌ๊ณ ๋ณ๊ฒฝํ๋ ๋ฉ์๋ ์์ฑ
- JuiceMaker: Juice Recipe๋ฅผ NestedType์ ํตํด ๊ตฌํ, ์ฌ๊ณ ์์ ๊ธฐ๋ฅ, ์ ์ฝ์ฌํญ์ ๋ฐ๋ฅธ ์๋ฌ์ฒ๋ฆฌ ๊ตฌํ
- 220831: ์ ๊ทผ์์ค ์ง์ ์ ์ํ Protocol ํ์ผ ์์ฑ ๋ฐ ์บก์ํ& ์๋ํ ๊ตฌํ
- ์ฐธ์กฐ๋๋ ๋ฉ์๋๋ค ๋ฐ๋ก extension ClassName: ProtocolName {} ๋ก ์ด๋
[STEP-2]
- 220906:
NotificationCenter
์ด์ฉ- ์๋ฆผ ์ ์ก ์, ์ฅฌ์ค์ ์ด๋ฆ๊ณผ ์ฅฌ์ค์์ฑ์ฌ๋ถ๋ฅผ userInfo์ ๋ด์ postํ๋๋ก ๊ตฌํ
- 220908: juiceMaker ์ธ์คํด์ค ์์ฑ ์์น
- FruitJuiceStoreViewController ๋ด๋ถ์์ ViewDidLoad ๊ธฐ์ค ๋ด๋ถ์ ์ธ๋ถ ์ค juiceMaker ์ธ์คํด์ค ์์ฑ ์์น์ ๋ํด ํ ์
- 220913: Modelํด๋ ๋ด๋ถ์ JuiceMaker.takeOrder๋ฉ์๋ ViewController.takeOrder๋ก ์์น ๋ณ๊ฒฝ
- Controller ๋จ์์์ ์๋ฌ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํด์ง์ ๋ฐ๋ผ NotificationCenter๊ธฐ๋ฅ ์ญ์
[STEP-3]
- 220916: ํ๋ฉด ์ ํ ์, ์ ๋ฌ๊ฐ ๋ฐฉ๋ฒ ๊ฒฐ์
- ์ฌ๊ณ ์ถ๊ฐ ํ๋ฉด ์ ํ ์, ์ฌ๊ณ ๋ณ๊ฒฝ์ ์ํด
class FruitStore()
vsfruitStock: [Fruit: Int]
๋ ์ค ์ด๋ค ๋ฐ์ดํฐํ์ ์ ๊ณต์ ํ ์ง์ ๋ํด ํ ์
- ์ฌ๊ณ ์ถ๊ฐ ํ๋ฉด ์ ํ ์, ์ฌ๊ณ ๋ณ๊ฒฝ์ ์ํด
- 220916: ์ฌ๊ณ ์ถ๊ฐ ํ๋ฉด์ผ๋ก์ ํ๋ฉด์ ํ๋ฐฉ๋ฒ์ ๋ํด ํ ์.
segue ์ฐ๊ฒฐ
vspresent()
- storyboard ์์ segue๋ฅผ ์ฐ๊ฒฐํด ํ๋ฉด ์ ํ
- ํ๋ฉด์ ํ ์ prepare ๋ฉ์๋๋ฅผ ์ด์ฉํด fruitStock๊ฐ ๊ณต์
.
โโโ Controller
โย ย โโโ AppDelegate.swift
โย ย โโโ FruitJuiceStoreViewController.swift
โย ย โโโ FruitStockEditorViewController.swift
โย ย โโโ JuiceMaker.swift
โย ย โโโ SceneDelegate.swift
โโโ Model
โย ย โโโ Enum
โย ย โย ย โโโ Variation.swift
โย ย โโโ Fruit
โย ย โย ย โโโ Fruit.swift
โย ย โย ย โโโ FruitStore.swift
โย ย โโโ Juice
โย ย โโโ Juice.swift
โย ย โโโ JuiceMaker.swift
โย ย โโโ JuiceMakerError.swift
โโโ Protocol
โย ย โโโ FruitStockDelegate.swift
โย ย โโโ FruitStoreProtocol.swift
โย ย โโโ JuiceMakerProtocol.swift
โโโ View
โโโ Base.lproj
โโโ LaunchScreen.storyboard
โโโ Main.storyboard
์ฃผ์ค ์ฃผ๋ฌธ ์ฑ๊ณต | ์ฃผ์ค ์ฃผ๋ฌธ ์คํจ |
---|---|
![]() |
![]() |
- ๊ณผ์ผ์ ์ฌ๊ณ ๋ฅผ ๊ด๋ฆฌํด์ฃผ๊ธฐ ์ํด ์ฌ๊ณ ๋ฅผ ์๋ฏธํ๋
fruitStore
์ ํ์ ์ ๊ณ ๋ฏผํ์ต๋๋ค. ๊ณผ์ผ์ ์ด๋ฆ๊ณผ ํด๋น๊ณผ์ผ์ ์ฌ๊ณ ๋ฅผ ๋์์ ํ์ ํ๊ธฐ ์ํด ๋์ ๋๋ฆฌ ํ์ ์ผ๋ก ๊ตฌํํ์ต๋๋ค. - ์ฌ๊ณ ํ์ธ์ ์ํด
Value
์ ์ ๊ทผํ ๋ ๋์ ๋๋ฆฌ์ ํน์ง์ ์ต์ ๋์ ์ฒดํฌํด์ค์ผํ์ต๋๋ค. ์ฝ๋์ ์ฌ์ฌ์ฉ์ฑ์ด ๋์ ๊ฒ ๊ฐ์ ์ต์ ๋ ๋ฐ์ธ๋ฉ ๋ฉ์๋๋ฅผ ์ถ๊ฐํ์ต๋๋ค.
- Juice ํ์ผ๋ด์
Recipe
ํ์ ์ ์์ฑ ํ ๋์,Netsted Types
์ ์ด๋ป๊ฒ ํ์ฉํ์ฌ ์ฌ์ฉํ ์ง ๊ณ ๋ฏผํ์์ต๋๋ค. User๊ฐ ์ ํํ Juice ์ค์์ ํ์ข ๋ฅ์ ๊ณผ์ผ์ ์ฌ์ฉํ์ฌ ์ ์กฐํ๋ ๊ฒฝ์ฐ์ ๋ ์ข ๋ฅ์ ๊ณผ์ผ์ ์ด์ฉํ์ฌ ์ ์กฐํ๋ ๊ฒฝ์ฐ๊ฐ ์์์ต๋๋ค. ์ด์ ๋ฐ๋ผ, ์ฒ์์๋ ๋๋ฒ์งธ ์ข ๋ฅ์ ๊ณผ์ผ๊ณผ ์๋์ ํํ์ ์ฌ์ฉํ๊ณ ์ต์ ๋๋ก ์ ์ธ์ ํ์ฌ ๊ตฌํํ์์ผ๋, ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๊ฒ ๋์์ต๋๋ค.- ๋ณต์กํ ํํ ์ฒ๋ฆฌ : ๋ ๋ฒ์งธ ์ข ๋ฅ์ ๊ณผ์ผ๊ฐ์ด ์ต์ ๋๋ก ์์ฑ๋๊ฒ ๋๋ค๋ฉด ๋ ๋ฒ ์ข ๋ฅ์ ๊ณผ์ผ ๊ฐ์ ์ฌ์ฉํ ๋ ๋ง๋ค ์ต์ ๋๋ฐ์ธ๋ฉ์ ํด์ผํ๋ ๋ฒ๊ฑฐ๋ก์์ด ์๊น๋๋ค.
- ๋ง์ฝ์ ์ธ ๋ฒ์งธ ์ฌ๋ฃ๋ฅผ ์ฌ์ฉํ๋ ์ฅฌ์ค๊ฐ ์๊ธด๋ค๋ฉด? : ์ธ ๋ฒ์งธ ํ๋กํผํฐ๋ฅผ ๋ค์ ์ถ๊ฐํด์ผ ํ๊ณ , ์ด๋ ์ฝ๋์ ์ ์ง๋ณด์๊ฐ ๋ณต์กํด์ง ์ ์์ต๋๋ค.
- ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ณ ์, ๊ธฐ์กด์ ๊ตฌํํ๋ ๋๋ฒ์งธ ๊ณผ์ผ ์ข ๋ฅ๋ฅผ ์ต์ ๋๋ก ์ง์ ํ๋ ๋ฐฉ๋ฒ์์ ๋ฐฐ์ด์ ์ด์ฉํ์ฌ ๊ณผ์ผ์ข ๋ฅ์ ํ์์๋์ ๋ฐฐ์ด์ ๋ด๋ ๋ฐฉ๋ฒ์ผ๋ก ๋ณ๊ฒฝํ์์ต๋๋ค.
// ๊ธฐ์กด Recipe ๊ตฌ์กฐ์ฒด
struct Recipe {
let first: (Fruit, Int)
let second: (Fruit, Int)?
}
// Recipe ๊ตฌ์กฐ์ฒด ๋ด๋ถ์ ํ๋กํผํฐ ๋ณ๊ฒฝ
struct Recipe {
let name: Fruit
let amount: Int
}
// 1๋ฒ ๋ฐฉ๋ฒ: ๊ธฐ์กด์ ์ต์
๋์ ํ์ฉํ์ฌ ๋ ์ํผ๋ฅผ ํํํ๋ ๋ฐฉ๋ฒ
var recipe: Recipe {
switch self {
case .strawberryJuice:
return Recipe(first: (.strawberry, 16), second: nil)
case .strawberryBananaJuice:
return Recipe(first: (.strawberry, 10), second: (.banana, 1))
}
// 2๋ฒ ๋ฐฉ๋ฒ: ๊ณ ๋ฏผ์ฌํญ์ ๋ฐ์ํ์ฌ ๋ฐฐ์ด๋ก ๋ ์ํผ๋ฅผ ํํํ๋ ๋ฐฉ๋ฒ
var recipe: [Recipe] {
switch self {
case .strawberryJuice:
return [Recipe(name: .strawberry, amount: 16)]
case .strawberryBananaJuice:
return [Recipe(name: .strawberry, amount: 10), Recipe(name: .banana, amount: 1)]
}
- ๋ฐฐ์ด์ ์ฌ์ฉํ๋ ๋ฐฉ์์ ์ฐ๊ฒ ๋๋ฉด, ์ถํ ์ผ์ ๋๋ ์คํ๊ณผ ๊ฐ์ ์ฌ๋ฃ์ ์ถ๊ฐ์ ๊ฒฝ์ฐ์๋ ์์ฝ๊ฒ
Recipe ๊ตฌ์กฐ์ฒด
๋ง ์์ ํ๋ฉด ๋๊ธฐ ๋๋ฌธ์ ์ ์ง๋ณด์์ ์ฉ์ด์ฑ์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
- [STEP-1] ์์ค์์๋ ๋จ์ํ๊ฒ
isEnoughStock()
๋ฉ์๋๋ง์ ์ด์ฉํด ๋จ์ํ๊ฒ ์ฌ๊ณ ๊ฐ ์์ ํด์ผํ ์๋ณด๋ค ์ ์ ๊ฒฝ์ฐ, ์ค๋ฅ ๋ฌธ๊ตฌ๋ฅผ ์ถ๋ ฅํด์ฃผ๋ ์ ๋๋กerror
๋ฅผ ํํํ๊ณ ์๋๋ฐ, ์ถํ ViewController ๋จ์๋ก ์์ ์ ๋ํ๊ฐ๋ค๋ฉดdo-try-catch
๋๋result
์ค์ ์ด๋ค ๋ฐฉ๋ฒ์ผ๋ก ์ด๋ ๋จ์์์ ๊ตฌํํด์ผํ ์ง ๊ณ ๋ฏผ์ค์ ์์ต๋๋ค. - [STEP-2] ๊ธฐ์กด์ ์ฌ๊ณ ๊ฐ ์ถฉ๋ถํ์ง ํ์ธํ๋ ๋ฉ์๋
isEnoughStock()
๋ฅผ ํ์ฉ ๋ฐ ์์ ํดcheckEnoughStock(juiceRecipe: [Juice.Recipe]) throws
๋ก ๋ณ๊ฒฝํด ์๋ฌ๋ฅผ ์ฒ๋ฆฌํ์ต๋๋ค. ๋ํ ์ฅฌ์ค๋ฅผ ๋ง๋๋ ๋ก์ง์ ViewController๋จ์๋ก ์ฎ๊น์ ๋ฐ๋ผJuiceMaker
์์ ์๋ฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์ ๋ค์ return ํด์ฃผ๋ ๋ฉ์๋๋ฅผ ์์ฑํ์ต๋๋ค.
- ๊ธฐ์กด์๋ JuiceMaker์ ์ฃผ์ค๋ฅผ ์ฃผ๋ฌธ๋ฐ๋ takeOrder๋ฉ์๋๋ฅผ ๊ตฌํํ์์ต๋๋ค. ๋ฉ์๋ ๋ด๋ถ์๋ NotificationCenter๊ฐ postํ ๋ด์ฉ์ ๋ฐ๋ผ, ์ฅฌ์ค ์ฃผ๋ฌธ ์์ ํ์ํ ํด๋น ๋ ์ํผ์ ๋ฐ๋ฅธ ๊ณผ์ผ์์ ํ์ธํ๋ ๋ฉ์๋๋ฅผ ํธ์ถํ๊ณ ๊ณผ์ผ์ฌ๊ณ ์ ๋ฌด์ ๋ฐ๋ฅธ ์ฑ๊ณต/์คํจ ์ผ๋ฟ์ ๋์์ฃผ๊ฒ ๋์์ต๋๋ค. ๊ทธ๋ฌ๋, ๋น๋์ง์ค๋ก์ง์ ๊ฐ๋ ์ ๋ํด ์ดํด๋ณด๊ณ takeOrder ๋ฉ์๋์ ์์น์ ๋ํด ๊ณ ๋ฏผํ๊ฒ ๋๋ฉด์ takeOrder ๋ฉ์๋์ ์์น๋ฅผ FruitJuiceStoreViewController๋ก ์ฎ๊ธฐ๊ฒ ๋๋ฉด์ NotificationCenter์ ์๋ฆผ์ ์ ์ก๋ฐ๊ฒ ๋ ์ด์ ๊ฐ ์ฌ๋ผ์ง๊ฒ ๋์ด ์ฌ์ฉํ์ง ์๊ฒ๋์์ต๋๋ค.
- ์ฅฌ์ค๋ฉ์ด์ปค ํ๋ฉด์์ ์ฌ๊ณ ์ถ๊ฐ ํ๋ฉด์ผ๋ก ํ๋ฉด์ ํ์ด ์ด๋ฃจ์ด์ง ๋
FruitStore()
ํด๋์ค๋ฅผ ๊ณต์ ํ ์ง,fruitStock: [Fruit: Int]
๊ฐ์ ๊ณต์ ํ ์ง์ ๋ํด ๊ณ ๋ฏผํ์ต๋๋ค. ํ์๋ค๊ณผ ํ ์ํ ํ ๋ค์๊ณผ ๊ฐ์ ์ด์ ๋กfruitStock
๊ฐ์ ๊ณต์ ํ๊ธฐ๋ก ๊ฒฐ์ ํ์ต๋๋ค.- ์ฒซ๋ฒ์งธ ์ด์ :
FruitStore()
์ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ง ์๊ธฐ ๋๋ฌธ์ ๋๋ค.fruitStock
ํ๋กํผํฐ๋ฅผ ์ ์ธํFruitStore()
๋ด๋ถ์์๋ค์ ์ฌ์ฉํ์ง ์์ ๊ณต์ ํ๊ธฐ ์ ํฉํ์ง ์๋ค๊ณ ํ๋จํ์ต๋๋ค. - ๋๋ฒ์งธ ์ด์ : ์ฐธ์กฐ ํ์
์ธ์ง ๊ฐ ํ์
์ธ์ง ๋ถ๋ถ๋ช
ํ ํ์
์ ๊ณต์ ํ๊ฒ ๋๋ค๋ฉด ์์ํ์ง ๋ชปํ ์ค๋ฅ๋ค์ด ๋ฐ์ํ ์ ์๊ธฐ ๋๋ฌธ์
fruitStock
๊ฐ์ ๊ณต์ ํ๊ธฐ๋ก ๊ฒฐ์ ํ์ต๋๋ค.
- ์ฒซ๋ฒ์งธ ์ด์ :
// 1๋ฒ ๋ฐฉ๋ฒ: Segueway๋ฅผ ํตํ ์ ํ
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let fruitStockEditorViewController = segue.destination as? FruitStockEditorViewController else { return }
fruitStockEditorViewController.delegate = self
fruitStockEditorViewController.editingFruitStock = receiveFruitStock()
}
// 2๋ฒ ๋ฐฉ๋ฒ: present๋ฅผ ์ด์ฉํ ์ ํ
@IBAction func touchUpEditButton(_ sender: Any) {
guard let fruitStockEditorViewController = self.storyboard?.instantiateViewController(identifier: "FruitStockEditorViewController") as? FruitStockEditorViewController else { return }
fruitStockEditorViewController.delegate = self
fruitStockEditorViewController.editingFruitStock = receiveFruitStock()
present(fruitStockEditorViewController, animated: true, completion: nil)
}
- ์ ์ฝ๋์ ๊ธฐ์ฌ๋ ๋๊ฐ์ง ๋ฐฉ๋ฒ ์ค, Segueway ๋ฅผ ํตํ ์ ํ๋ฐฉ๋ฒ์ ์ ํํ์ต๋๋ค.
- ์ฒซ๋ฒ์งธ ์ด์ : ํ์ฌ๋ ๊ฐ์ Storyboard์์ ์กด์ฌํ๋ ๋๊ฐ์ ViewController๋ฅผ ์ฐ๊ฒฐํ๋ ์ ๋์ ํ๋ก์ ํธ ์ด๊ธฐ์ ์ด์๊ฐ์ ๋ฐฉ๋ฒ๋ ๊ด์ฐฎ๋ค๊ณ ์๊ฐํ์ต๋๋ค.
- ๋๋ฒ์งธ ์ด์ :
FruitStockEditorViewController
๋ก ์ด๋๋๋ ๋ก์ง์ด ๋ ๊ฐ์ง๋ผ์ ํ ๋ฒ๋ง ์์ฑํด๋ ๋๋ segueway ๋ฐฉ์์ ์ ํํดprepare
๋ฅผ overrideํ์ฌ ์ฌ์ฉํ์ต๋๋ค.
- ๋ฉ์๋์ ๊ธฐ๋ฅ๋จ์ ๋ถ๋ฆฌ
- ๊ฐ ํ์ ๋ด ๋น์ง๋์ค ๋ก์ง์ ๋ํ ๊ณ ๋ฏผ
- Nested Types ์ฌ์ฉ
- Initalization์ ๋ํ ๊ณ ๋ฏผ
- Class์ Struct ํ์ ์ฐจ์ด์ ๋ฐ๋ฅธ ์ด์ฉ
- ์ ๊ทผ์ ์ด ๋จ๊ณ์ ๋ฐ๋ฅธ ์๋ํ
- UIkit ์ปดํฌ๋ํธ์ ๋ํ ์ดํด์ ํ์ฉ
- ํ๋ฉด ์ ํ๋ฐฉ์์ ๋ํ ์ดํด
- IBOulet๊ณผ IBAction์ ๋ํ ์ดํด
- Alret๊ณผ Stepper์ ํ์ฉ
- ํ๋ฉด ์ฌ์ด์ ๋ฐ์ดํฐ ๊ณต์
- API Design Guidlines
- Swift Style Guide
- The Basics
- miro.com - flow chart
- drawio - UML
- The Swift Programming Language (Swift 5.7)