Skip to content

๐Ÿป iOS ์ปค๋ฆฌ์–ด ์Šคํƒ€ํ„ฐ ์บ ํ”„ ๐Ÿงƒ ์ฅฌ์Šค ๋ฉ”์ด์ปค ํ”„๋กœ์ ํŠธ

Notifications You must be signed in to change notification settings

cherrishRed/ios-juice-maker

ย 
ย 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿงƒ ์ฅฌ์Šค ๋ฉ”์ด์ปค

ํ”„๋กœ์ ํŠธ ๊ธฐ๊ฐ„ 2022.02.21 ~ 2022.03.11

ํŒ€์› : @cherrishRed @saafaaari / ๋ฆฌ๋ทฐ์–ด : @stevenkim18

๋ชฉ์ฐจ

ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ

๐Ÿงƒ ์ฃผ์Šค๋ฅผ ์ฃผ๋ฌธํ•˜์„ธ์š”!

โ˜‘๏ธ ํ’ˆ์ ˆ๋œ ์ฃผ์Šค๋Š” ํšŒ์ƒ‰์ž…๋‹ˆ๋‹ค

๐Ÿ“ ํ’ˆ์ ˆ์ด์—ฌ๋„ ๊ดœ์ฐฎ์•„์š” ์žฌ๊ณ ๋ฅผ ์ˆ˜์ •ํ•˜์„ธ์š”

์ฃผ์Šค ์ฃผ๋ฌธ

  • ์ฃผ์Šค๊ฐ€ ์žฌ๊ณ ๊ฐ€ ์žˆ์–ด ์ฃผ๋ฌธ์ด ๊ฐ€๋Šฅํ•  ๋•Œ ์ฃผ์Šค๊ฐ€ ๋‚˜์™”๋‹ค๋Š” ์•Œ๋ฆผ ํ‘œํ˜„, ์—†๋‹ค๋ฉด ์žฌ๋ฃŒ๊ฐ€ ์—†๋‹ค๋Š” ์•Œ๋ฆผ๊ณผ ์žฌ๊ณ ๋ฅผ ์ˆ˜์ •ํ• ์ง€์— ๋Œ€ํ•œ ์–ผ๋Ÿฟ ํ‘œํ˜„
  • ์žฌ๊ณ ๊ฐ€ ์žˆ์–ด ์ฃผ๋ฌธ์ด ๊ฐ€๋Šฅํ•œ ์ฃผ์Šค๋Š” ๋ฒ„ํŠผ์ด ํŒŒ๋ž‘์ƒ‰, ์—†์–ด ์ฃผ๋ฌธ์ด ๋ถˆ๊ฐ€๋Šฅํ•œ ์ฃผ์Šค๋Š” ๋ฒ„ํŠผ์ด ํšŒ์ƒ‰์œผ๋กœ ํ‘œํ˜„

์žฌ๊ณ  ์ˆ˜์ •

  • ์žฌ๊ณ  ์ˆ˜์ •ํ™”๋ฉด์œผ๋กœ ๋„˜์–ด๊ฐ€ ์›ํ•˜๋Š” ๋งŒํผ ์žฌ๊ณ  ์ˆ˜์ • ํ›„ "์˜ˆ" ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์ ์šฉ
  • "์•„๋‹ˆ์š”" ๋ฒ„ํŠผ์„ ํด๋ฆญ์‹œ ์žฌ๊ณ ๊ฐ€ ์ˆ˜์ •๋˜์ง€ ์•Š๊ณ , ์ฐฝ ์ข…๋ฃŒ

ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

juiceMakerUML

๊ฐœ๋ฐœํ™˜๊ฒฝ ๋ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

swift xcode

ํ‚ค์›Œ๋“œ

Modality Alert Navigation Stepper AutoLayout delegate Protocol CustomStringConvertible

[STEP 1]

STEP 1 PR

๊ณ ๋ฏผํ•œ ์ 

  • ์ดˆ๊ธฐ๊ฐ’ ์„ค์ •์— ๊ด€ํ•œ ์ด์Šˆ
  • ํ•„์š”์—†๋Š” ๊ฐ’ VS ์กฐ๊ฑด๋ฌธ ๋ฐ˜๋ณต๋ฌธ ์ค‘์ฒฉ
  • for ๋ฌธ ์•ˆ์˜ guard ์‚ฌ์šฉ์— ๋Œ€ํ•œ ๋ฆฌ๋ทฐ์–ด๋‹˜์˜ ์ƒ๊ฐ
  • ํด๋ž˜์Šค ๋‚ด๋ถ€์˜ ์—ด๊ฑฐํ˜• ์ ‘๊ทผ์— ๊ด€ํ•ด
  • ์—ด๊ฑฐํ˜•์˜ ์œ„์น˜์— ๋”ฐ๋ฅธ ๋ฉ”๋ชจ๋ฆฌ์  ์ฐจ์ด
  • MVC์— ๋Œ€ํ•œ ๊ฐ ๊ฐœ์ฒด์˜ ๊ธฐ๋Šฅ์˜ ๋ฒ”์œ„

๋ฐฐ์šด ๊ฐœ๋…

  • ์—ด๊ฑฐํ˜• ์‚ฌ์šฉ๋ฒ•
  • ํด๋ž˜์Šค์™€ ๊ตฌ์กฐ์ฒด(์ฐธ์กฐํƒ€์ž…๊ณผ, ๊ฐ’ํƒ€์ž…)์˜ ์ฐจ์ด
  • ๊ฐ’ํƒ€์ž…์˜ ๊ฐ’ ๋ณ€๊ฒฝ์— ๋”ฐ๋ฅธ ๋ฉ”๋ชจ๋ฆฌ์˜ ๋ณ€ํ™” ๋ฐ mutatingํ‚ค์›Œ๋“œ
  • ํƒ€์ž… ์ดˆ๊ธฐํ™”์˜ ๋ฐฉ๋ฒ•๊ณผ ๊ฐ ์ฐจ์ด ๋ฐ ํ”„๋Ÿฌํผํ‹ฐ์˜ ์ดˆ๊ธฐํ™” ์‹œ์ ์— ๋Œ€ํ•ด
  • nestType
  • ํ•จ์ˆ˜์™€ ํŒŒ๋ผ๋ฏธํ„ฐ ๋„ค์ด๋ฐ์— ๋Œ€ํ•ด
  • guarad๋ฌธ๊ณผ if๋ฌธ์˜ ์ฐจ์ด

nestType(enum)

struct JuiceMaker {
    enum Juice {
    //๊ตฌํ˜„์‚ฌํ•ญ 
    }
}

nesteType ํƒ€์ž…์„ ์„ ์–ธํ•  ๊ฒฝ์šฐ JuiceMaker.Juice ์ฒ˜๋Ÿผ ํƒ€์ž…์œผ๋กœ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

nestType์œผ๋กœ ์–ป๊ฒŒ ๋˜๋Š” ์žฅ์ ์€ Juice ๋ผ๋Š” ํƒ€์ž…์„ ์ ‘๊ทผํ•  ๋•Œ JuiceMaker.Juice ๋กœ ์ ‘๊ทผํ•˜๊ฒŒ ํ•˜์—ฌ Juice๊ฐ€ JuiceMaker์— ์—ฐ๊ด€๋œ ๊ฐ’ ์ž„์„ ์ •ํ™•ํžˆ ํ•˜๋Š”๋ฐ์— ์žˆ๋‹ค. ์ „์—ญ์œผ๋กœ ๋นผ๋„ ๋ฌธ์ œ ์—†์ง€๋งŒ, ํ˜„์žฌ๋Š” Juice ์˜ ํƒ€์ž…์ด JuiceMaker ์•ˆ์—์„œ๋งŒ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ๋‹ค๋ณด๋‹ˆ ์—ฌ๊ธฐ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ฐ’์ด๋‹ค ๋ผ๋Š” ์˜๋ฏธ๋ฅผ ์ฝ”๋“œ์— ๋‹ด๊ณ  ์‹ถ์—ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ดํ›„ ์Šคํ…์—์„œ ๋‹ค๋ฅธ ๊ฐ์ฒด์—์„œ Juice ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด์„œ Juice ํƒ€์ž…์„ ๋ฐ–์œผ๋กœ ๋นผ๊ธฐ๋กœ ๋…ผ์˜ํ–ˆ๊ณ , ๊ทธ ์ค‘ JuiceMaker ์•ˆ์—์„œ๋งŒ ์‚ฌ์šฉ๋˜๋Š” recipe ์ด๋ผ๋Š” ์—ฐ์‚ฐ ํ”„๋กœํผํ‹ฐ๋ฅผ extension ์œผ๋กœ JuiceMaker ๋‚ด๋ถ€์— ์„ ์–ธํ•ด ์ฃผ๊ฒŒ ๋˜์—ˆ๋‹ค.

์ด๋‹ˆ์…œ๋ผ์ด์ ธ

class FruitStore {
    private let defaultStock: Int = 10
    var stock: [Fruit: Int] = [.strawberry: self.defaultStock,
                     .banana: self.defaultStock,
                     .pineapple: self.defaultStock,
                     .kiwi: self.defaultStock,
                     .mango: self.defaultStock]
}
//์ปดํŒŒ์ผ ์˜ค๋ฅ˜: Cannot find 'self' in scope

์œ„ ์ฒ˜๋Ÿผ ๊ธฐ๋ณธ ํ”„๋กœํผํ‹ฐ ์ดˆ๊ธฐํ™” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ selfํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ์ด์œ ๋Š” ์‹œ์ ์˜ ๋ฌธ์ œ์ธ๋ฐ ํƒ€์ž… ๋‚ด๋ถ€์—์„œ ๊ธฐ๋ณธ ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ดˆ๊ธฐํ™”ํ–ˆ์„ ์‹œ ์ดˆ๊ธฐํ™” ์‹œ์ ์ด defaultStock์™€ stock๊ฐ€ ๊ฐ™๊ธฐ ๋•Œ๋ฌธ์— ์ปดํŒŒ์ผ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„  ์‹œ์ ์„ ๋‹ฌ๋ฆฌ ์ฃผ๋Š” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”๋ฐ lazyํ‚ค์›Œ๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ ์‹œ์ ์„ ๋‹ค๋ฅด๊ฒŒ ํ•ด์ฃผ๊ฑฐ๋‚˜, ์ด๋‹ˆ์…œ๋ผ์ด์ ธ init()๋‚ด๋ถ€์—์„œ ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

class FruitStore {
    private(set) var stock: [Fruit: Int]
    
    init(defaultStock: Int = 10) {
        stock = [.strawberry: defaultStock,
                 .banana: defaultStock,
                 .pineapple: defaultStock,
                 .kiwi: defaultStock,
                 .mango: defaultStock]
    }
}

๋•Œ๋ฌธ์—, ์œ„์™€๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ init์˜ ์ „๋‹ฌ์ธ์ž์— ๊ธฐ๋ณธ๊ฐ’์„ ์„ค์ •ํ•˜์—ฌ ์œ ์—ฐํ•œ ์ดˆ๊ธฐํ™”๋ฅผ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ด๋ฅผ ํ•ด๊ฒฐํ•˜์˜€๋‹ค. ์ด๋ฅผ ๊ณต๋ถ€ํ•˜๋ฉฐ, ์—ฌ๋Ÿฌ ์ดˆ๊ธฐํ™” ๋ฐฉ๋ฒ•์„ ์–ธ์ œ ์–ด๋–ค ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ• ์ˆ˜ ์žˆ์„์ง€์™€

ํƒ€์ž… ํ”„๋กœํผํ‹ฐ๊ฐ€ ํ•ญ์ƒ ๊ฐ™์€ ๊ฐ’์„ ๊ฐ€์ง„๋‹ค๋ฉด, ์ดˆ๊ธฐํ™” ๊ตฌ๋ฌธ ์‚ฌ์šฉ๋ณด๋‹ค๋Š” ๊ธฐ๋ณธ ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋žŒ์งํ•˜๋‹ค. ์™œ ๋‚ดํ•˜๋ฉด, ๊ธฐ๋ณธ ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜์˜€์„ ๋•Œ ์ฝ”๋“œ๊ฐ€ ๊ฐ„๊ฒฐํ•˜์ง€๊ณ  ๋ช…ํ™•ํ•ด์ง€๋ฉฐ, ํ”„๋กœํผํ‹ฐ ํƒ€์ž…์„ ์œ ์ถ”ํ•˜๊ธฐ ์‰ฝ๋‹ค. ํ•˜์ง€๋งŒ, ์ธ์Šคํ„ด์Šค๋งˆ๋‹ค ๋‹ค๋ฅธ ํ”„๋กœํผํ‹ฐ ์ดˆ๊นƒ๊ฐ’์„ ์„ค์ •ํ•ด ์ค˜์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ, ์ดˆ๊นƒ๊ฐ’์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ์ดˆ๊ธฐํ™” ๊ตฌ๋ฌธ์‚ฌ์šฉ์ด ์œ ์šฉํ•˜๋‹ค.

์ดˆ๊ธฐํ™”์—” ๋‹จ๊ณ„๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ฐฐ์šธ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

1๋‹จ๊ณ„

  • ์ง€์ •๋œ ๋˜๋Š” ํŽธ์˜ ์ดˆ๊ธฐํ™” ๊ตฌ๋ฌธ์€ ํด๋ž˜์Šค์—์„œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
  • ํด๋ž˜์Šค์— ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค์— ๋Œ€ํ•œ ๋ฉ”๋ชจ๋ฆฌ๋Š” ํ• ๋‹น๋ฉ๋‹ˆ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ๋Š” ์•„์ง ์ดˆ๊ธฐํ™” ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
  • ํด๋ž˜์Šค์— ๋Œ€ํ•œ ์ง€์ •๋œ ์ดˆ๊ธฐํ™” ๊ตฌ๋ฌธ์€ ํด๋ž˜์Šค์— ์˜ํ•ด ๋„์ž…๋œ ๋ชจ๋“  ์ €์žฅ๋œ ํ”„๋กœํผํ‹ฐ๊ฐ€ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ €์žฅ๋œ ํ”„๋กœํผํ‹ฐ์— ๋Œ€ํ•œ ๋ฉ”๋ชจ๋ฆฌ๋Š” ์ดˆ๊ธฐํ™” ๋ฉ๋‹ˆ๋‹ค.
  • ์ง€์ •๋œ ์ดˆ๊ธฐํ™” ๊ตฌ๋ฌธ์€ ์ž์ฒด ์ €์žฅ๋œ ํ”„๋กœํผํ‹ฐ์— ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์ƒ์œ„ ํด๋ž˜์Šค ์ดˆ๊ธฐํ™” ๊ตฌ๋ฌธ์— ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.
  • ์ด๊ฒƒ์€ ์ตœ์ƒ์œ„ ์ฒด์ธ๊นŒ์ง€ ํด๋ž˜์Šค ์ƒ์† ์ฒด์ธ ์œ„๋กœ ๊ณ„์†๋ฉ๋‹ˆ๋‹ค.
  • ์ตœ์ƒ์œ„ ์ฒด์ธ์— ๋„๋‹ฌํ•˜๊ณ  ์ฒด์ธ์— ๋งˆ์ง€๋ง‰ ํด๋ž˜์Šค๊ฐ€ ๋ชจ๋“  ์ €์žฅ๋œ ํ”„๋กœํผํ‹ฐ๊ฐ€ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ณ  ํ™•์ธํ•˜๋ฉด ์ธ์Šคํ„ด์Šค์˜ ๋ฉ”๋ชจ๋ฆฌ๋Š” ์™„๋ฒฝํ•˜๊ฒŒ ์ดˆ๊ธฐํ™” ๋˜์—ˆ๋‹ค๊ณ  ๊ฐ„์ฃผํ•˜๊ณ  ์ฒซ๋‹จ๊ณ„๊ฐ€ ์™„๋ฃŒ๋ฉ๋‹ˆ๋‹ค.

2๋‹จ๊ณ„

  • ์ฒด์ธ์˜ ์ตœ์ƒ์œ„์—์„œ ์•„๋ž˜๋กœ ๋‚ด๋ ค๊ฐ€๋ฉด ์ฒด์ธ์— ๊ฐ ์ง€์ •๋œ ์ดˆ๊ธฐํ™” ๊ตฌ๋ฌธ์€ ์ธ์Šคํ„ด์Šค๋ฅผ ์ถ”๊ฐ€๋กœ ์‚ฌ์šฉ์ž ์ •์˜ํ•  ์ˆ˜ ์žˆ๋Š” ์˜ต์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ดˆ๊ธฐํ™” ๊ตฌ๋ฌธ์€ ์ด์ œ self ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๊ณ  ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋“ฑ์— ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋งˆ์ง€๋ง‰์œผ๋กœ ์ฒด์ธ์— ๋ชจ๋“  ํŽธ์˜ ์ดˆ๊ธฐํ™” ๊ตฌ๋ฌธ์€ ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉ์ž ์ •์˜ํ•˜๊ณ  self ๋กœ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋Š” ์˜ต์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณต์‹๋ฌธ์„œ๋ฅผ ์ธ์šฉํ•˜์—ฌ ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.

guard if ๋ฌธ ์ฐจ์ด if์™€ guard๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ์ฝ”๋“œ๋ฅผ ์ฝ๋Š” ํ๋ฆ„์ด ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ๋‹ค.

guard checkOneStock(of: juice, with: list) else { return false }
if checkOneStock(of: juice, with: list) == false { return false }

์ ์ ˆํ•œ ์ƒํ™ฉ์— ์ž˜ ์„ ํƒํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

[STEP 2]

STEP 2 PR

๊ณ ๋ฏผํ•œ ์ 

  • ์–ด๋ ค ๋ฒ„ํŠผ์— ๋Œ€ํ•œ ์•ก์…˜์„ ํ•˜๋‚˜์˜ IBAction์œผ๋กœ ์ฒ˜๋ฆฌํ•ด์ค„ ๊ฒƒ์ธ๊ฐ€
  • ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ค„ ๊ฒƒ์ธ๊ฐ€
  • ๋‹ค๋ฅธ ์ƒํ™ฉ์— ๋ณด์ด๋Š” ์–ผ๋Ÿฟ์— ๋Œ€ํ•œ ํ•จ์ˆ˜๋ฅผ ๋ถ„๋ฆฌํ•  ๊ฒƒ์ธ๊ฐ€? ํ†ตํ•ฉํ•  ๊ฒƒ์ธ๊ฐ€?
  • ํ™”๋ฉด์ „ํ™˜์„ ๋ชจ๋‹ฌ์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ธ๊ฐ€ ๋‚ด๋น„๊ฒŒ์ด์…˜์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ธ๊ฐ€?

๋ฐฐ์šด ๊ฐœ๋…

  • ๋ชจ๋‹ฌ๊ณผ ๋„ค๋น„๊ฒŒ์ด์…˜์˜ ์ฐจ์ด
  • ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด
  • ์—๋Ÿฌ ํ•ธ๋“ค๋ง
  • CustomStringConvertible
  • KVO, Notification center ์˜ ์‚ฌ์šฉ๋ฒ•

์‹ฑ๊ธ€ํ†ค ํŒจํ„ด ์‹ฑ๊ธ€ํ†ค์€ ์—ฌ๋Ÿฌ๊ณณ์—์„œ ๊ฐ™์€ ์ธ์Šคํ„ด์Šค์— ์ ‘๊ทผํ•ด ๋ชจ๋‘๊ฐ€ ๊ฐ™์ด ๊ฐ’์„ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉ๋œ๋‹ค.

์žฅ์ ์€ ์–ด๋””์—์„œ๋‚˜ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ์ „์—ญ์ธ์Šคํ„ด์Šค ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ๊ฐ€ ๊ฐ„๊ฒฐํ•˜๊ณ  ํŽธํ•˜๋‹ค. ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ ˆ์•ฝํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹จ์ ์€ ๊ฐ์ฒด์ง€ํ–ฅ ์„ค๊ณ„ ์›์น™์— ์–ด๊ธ‹๋‚œ๋‹ค. ๊ฐ์ฒด์ง€ํ–ฅ์˜ ์›์น™ ์ค‘ ๊ฐœ๋ฐฉ ํ์‡  ์›์น™์œผ๋กœ MVC ๊ฐ๊ฐ์˜ ์—ญํ• ์ด ์ž˜ ๋ถ„๋ฆฌ๋˜์–ด์•ผ ํ•˜๋Š”๋ฐ, ์‹ฑ๊ธ€ํ†ค์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์ด ์…‹์˜ ๊ฒฐํ•ฉ๋„๊ฐ€ ์˜ฌ๋ผ๊ฐ€ ๊ฐ๊ฐ์˜ ์—ญํ• ์ด ๋ชจํ˜ธํ•ด ์ง€๊ฒŒ ๋œ๋‹ค. ๋˜ํ•œ ๋ฉ€ํ‹ฐ ์“ฐ๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ๋™๊ธฐํ™” ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ 2๊ฐœ์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ๋ฌธ์ œ์ ์ด ๋‚˜ํƒ€๋‚œ๋‹ค๊ณ  ํ•œ๋‹ค.

Swift์—์„œ๋Š” ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜ ์„ผํ„ฐ, NSFileManager, NSWorkspace, UIApplication ๊ทธ๋ฆฌ๊ณ  UIAccelerometer ๋“ฑ์ด ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค.

์ฒ˜์Œ์—” ์žฌ๊ณ  ๊ด€๋ฆฌ์— ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ํ™œ์šฉํ•˜์˜€์ง€๋งŒ, swift ์—์„œ ์‹ฑ๊ธ€ํ†ค์„ ์‚ฌ์šฉํ•˜๋Š” ์˜๋„์™€ (์ผ์„ ํ•ด์ฃผ๋Š” ์—ญํ• ) ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ์˜๋„๊ฐ€ ๋งž์ด ์•Š๋‹ค๊ณ  ํŒ๋‹จํ•ด ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝํ•˜์˜€๋‹ค.

KVO, Notification center ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์—์„œ 1๋Œ€ 1๋กœ ๊ฐ’์„ ์ „๋‹ฌํ•˜๋Š”๋ฐ ํŠนํ™”๋˜์–ด ์žˆ๋Š” KVO๋กœ ๋กœ์ง์„ ๋ณ€๊ฒฝํ•˜๋ ค ํ•˜์˜€์œผ๋‚˜,

class FruitStore: NSObject {
    //static var shared = FruitStore()
    @objc dynamic var stock: [Fruit: Int]
    
    private init(defaultStock: Int = 10) {
        stock = [.strawberry: defaultStock,
                     .banana: defaultStock,
                     .pineapple: defaultStock,
                     .kiwi: defaultStock,
                     .mango: defaultStock]
        }
}
//์ปดํŒŒ์ผ ์˜ค๋ฅ˜: Property cannot be marked @objc because its type cannot be represented in Objective-C

์œ„์™€ ๊ฐ™์ด, enum ์ด ๋“ค์–ด์žˆ๋Š” dictionary ํƒ€์ž… ๊ฐ’์„ ์ „๋‹ฌ ํ•  ์ˆ˜ ์—†์–ด ์ ์šฉํ•˜์ง€ ๋ชปํ–ˆ๋‹ค.(enum ํƒ€์ž…์€ NSObject๋ฅผ ์ƒ์† ๋ฐ›์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์— KVO ๋ฐฉ์‹์œผ๋กœ ์˜ฎ๊ธธ ์ˆ˜๊ฐ€ ์—†๋‹ค.)

func changeStock(of fruit: Fruit, to numberOfFruit: Int) {
        guard var inStock: Int = stock[fruit] else { return }
        inStock += numberOfFruit
        stock[fruit] = inStock
        NotificationCenter.default.post(name: Notification.Name("notificationStock"),
                                        object: nil,
                                        userInfo: ["fruit": fruit,
                                                   "stock": inStock]
        )
    }
override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        NotificationCenter.default.addObserver(self, selector: #selector(updateFruitLable(_:)), name: Notification.Name("notificationStock"), object: nil)
        
    }
@objc private func updateFruitLable(_ notification: Notification) {
        guard let fruitName = notification.userInfo?["fruit"] as? Fruit else { return }
        guard let fruitStock = notification.userInfo?["stock"] as? Int else { return }
        print(fruitName, fruitStock)  
    }

๋•Œ๋ฌธ์— ์œ„์™€ ๊ฐ™์ด, 1๋Œ€ n ๋ฐฉ์‹์ด๊ธด ํ•˜์ง€๋งŒ ๊ฐ’์„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋Š” Notification Center ๋ฅผ ์ฑ„ํƒํ•˜์—ฌ ๊ฐ’์„ ์ „๋‹ฌํ•˜์˜€๋‹ค. ํ•˜์ง€๋งŒ ๋„˜๊ฒจ์ฃผ๋Š” ๊ฐ’์˜ ์–‘์˜ ๋น„ํ•ด ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์กŒ๊ณ  ์–ด๋””์—์„œ ๊ฐ’์„ ๋ณด๋‚ด๋Š”์ง€ ์ถ”์ ํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต๊ณ  ํ˜•๋ณ€ํ™˜์„ ํ•ด์ค˜์•ผ ํ•˜๋Š” ๋‹จ์  ๋“ฑ์œผ๋กœ ๊ฒฐ๊ตญ ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ฐ’์„ ๋„˜๊ฒจ์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝํ•˜์˜€๋‹ค.

๋‹ค์–‘ํ•œ ํ™”๋ฉด์ „ํ™˜ ๋ฐฉ๋ฒ• ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉฐ, ํ™”๋ฉด์ „ํ™˜์— ๋Œ€ํ•œ ์ด์Šˆ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค. ํ™”๋ฉด ์ „ํ™˜์˜ ๋ฐฉ๋ฒ•์€ ์Šคํ† ๋ฆฌ๋ณด๋“œ์—์„œ ์ง์ ‘ Segue๋ฅผ ์ด์šฉํ•˜์—ฌ ์ „ํ™”ํ•ด์ฃผ๋Š” ๋ฐฉ๋ฒ• ๋˜๋Š”, ์ฝ”๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ Navigation๋ฐฉ์‹์œผ๋กœ Pushํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ Modally๋ฐฉ์‹์œผ๋กœ Present ํ•ด์ฃผ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

    @IBAction func moveStockCorrectionView(_ sender: UIButton) {
        let stockCorrectionView = self.storyboard?.instantiateViewController(withIdentifier: "stockCorrection")
        self.present(stockCorrectionView!, animated: true, completion: nil)
        }

        stockCorrectionView?.modalTransitionStyle = .coverVertical
        stockCorrectionView?.modalPresentationStyle = .automatic

ํ”„๋กœ์ ํŠธ์—์„  Modally๋ฐฉ์‹์œผ๋กœ Present ํ•ด์ฃผ๋Š” ๋ฐฉ๋ฒ•์„ ์ฑ„ํƒํ•˜์˜€๊ณ , TransitionStyle๊ณผ PresentationStyle์€ ๊ธฐ๋ณธ๊ฐ’์ธ .coverVertical .automatic์„ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

[STEP 3]

๊ณ ๋ฏผํ•œ ์ 

  • ๋ชจ๋‹ฌ์„ ํ™œ์šฉํ•œ ๋ทฐ ์ด๋™์—์„œ ์ค‘๊ฐ„ ๋„ค๋น„๊ฒŒ์ด์…˜์ปจํŠธ๋กค๋Ÿฌ ๋•Œ๋ฌธ์—, ๋งŒ๋“  ๋ทฐ ์ธ์Šคํ„ด์Šค์™€ ์‹ค์ œ ์ด๋™๋œ ๋ทฐ์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋‹ฌ๋ž๋˜ ๋ฌธ์ œ
  • ํ™”๋ฉด๊ฐ„ ๋ฐ์ดํ„ฐ ์ด๋™์— ๊ด€ํ•œ ๋ฌธ์ œ

๋ฐฐ์šด ๊ฐœ๋…

  • MVC
  • delegate
  • protocol
  • auto Layout

MVC ์ฒ˜์Œ MVC ๋””์ž์ธ ํŒจํ„ด์— ๋Œ€ํ•ด ์ƒ๊ฐํ•ด ๋ณด๋ฉฐ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ตฌ์ƒํ•˜์˜€๋‹ค. ๋•Œ๋ฌธ์— ์ฒซ ๊ณ ๋ฏผ์€ "๊ฐ ๊ฐœ์ฒด๊ฐ€ ํŠน์„ฑ๊ณผ ํ–‰์œ„๋ฅผ ์–ด๋””๊นŒ์ง€ ๋‘˜ ๊ฒƒ์ด๋ƒ?"๋ผ๋Š” ๊ถ๊ธˆ์ฆ์žˆ์—ˆ๋‹ค. MVC ๋””์ž์ธ ํŒจํ„ด์ด ์ƒ๊ฒจ๋‚œ ํ•ต์‹ฌ์€ ์œ ์ง€ ๋ณด์ˆ˜๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๊ณ , ๊ทธ๋ž˜์„œ ์ฒ˜์Œ์—” ๋ชจ๋ธ์„ ๋‹จ์ˆœํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด๋Š” ๊ทธ๋ฆ‡์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์˜€๋‹ค. ์ปจํŠธ๋กค์ด ๋ชจ๋“  ๊ธฐ๋Šฅ์  ํ•จ์ˆ˜๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋„๋ก ์„ค๊ณ„ํ•˜๋Š” ๋ฐฉํ–ฅ์ด ์œ ์ง€ ๋ณด์ˆ˜์— ๋” ์ ํ•ฉํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์ง€๋งŒ, ์ปจํŠธ๋กค์˜ ์ •์˜๋ฅผ ์ƒ๊ฐํ•ด ๋ดค์„ ๋•Œ, "์ค‘๊ณ„์ž", "ํ†ต๋กœ"์ด๋Ÿฌํ•œ ํ‚ค์›Œ๋“œ๊ฐ€ ๋ถ™๋Š”๋‹ค๋Š” ๊ฒƒ๊ณผ "์ปจํŠธ๋กค์€ ์žฌ์‚ฌ์šฉ์„ ์ž˜ ํ•˜์ง€ ์•Š๋Š”๋‹ค"๋ผ๋Š” ๋ง์„ ๊ณ ๋ คํ•ด. ์ปจํŠธ๋กค์€ ์ •๋ง ์—ฐ๊ฒฐ์‹œ์ผœ์ฃผ๊ณ  ๋ทฐ์™€ ๋ชจ๋ธ์ด ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ์ •๋„์˜ ๊ธฐ๋Šฅ๋งŒ์„ ๊ตฌํ˜„ํ•˜๊ณ , ๋ชจ๋ธ์„ ์ค‘์ ์ ์œผ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ์„ค์ •ํ–ˆ๋‹ค. ๋•Œ๋ฌธ์— ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ์™€ ๊ฐ™์ด FruitStore์™€ JuiceMaker ๋ชจ๋ธ์ด ์žˆ๊ณ , MainViewController์™€ ManagingStockViewController ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์กด์žฌํ•œ๋‹ค. ํ•˜์ง€๋งŒ, ios์—์„œ View์™€ Controller๊ฐ€ ๋งค์šฐ ๋ฐ€์ ‘ํ•ด ์žˆ๋‹ค๋Š” ํŠน์„ฑ์ด ์žˆ์–ด, ํ”„๋กœ์ ํŠธ๊ฐ€ ์ง„ํ–‰๋˜๋ฉฐ ๋ชจ๋ธ์˜ ๊ธฐ๋Šฅ์ด ์ค„๊ณ , ์ปจํŠธ๋กค๋Ÿฌ์˜ ์—ญํ• ์ด ์ ์  ์ปค์ง€๋Š” ํ˜„์ƒ์„ ๋ฐœ๊ฒฌํ–ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ ์„ ๋ณด์™„ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์–‘ํ•œ ๋””์ž์ธ ํŒจํ„ด์„ ๊ณต๋ถ€ํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ƒ๊ฐ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์—ˆ๋‹ค. delegate delegate ํŒจํ„ด์ด๋ž€, ์›๋ž˜ ๋‚˜์˜ ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์ฒ˜๋ฆฌํ•  ๊ถŒํ•œ์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์„œ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•  ์ผ์„ ๋‹ค๋ฅธ ์˜ค๋ธŒ์ ํŠธ์—๊ฒŒ ๊ถŒํ•œ์„ ๋„˜๊ฒจ์ฃผ์–ด์„œ ๋‹ค๋ฅธ ์˜ค๋ธŒ์ ํŠธ์—์„œ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•ด์ฃผ๋Š” ํŒจํ„ด์ด๋‹ค.

manage ๋ทฐ์—์„œ main ๋ทฐ๋กœ ์ด๋™ ํ•  ๋•Œ์—๋Š” ๋ทฐ์˜ ์ƒ๋ช…์ฃผ๊ธฐ ๋•Œ๋ฌธ์— (๋ชจ๋‹ฌ๋กœ ์ฐฝ์„ ๋„์› ๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์‹œ main ์œผ๋กœ ๋Œ์•„์˜ฌ ๋•Œ์— viewWillAppear ๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์—์„œ) manage ๋ทฐ๊ฐ€ ์‚ฌ๋ผ์งˆ ๋•Œ ๋ผ๋ฒจ์˜ ๊ฐ’์„ ์—…๋ฐ์ดํŠธ ํ•ด์ฃผ์–ด์•ผ ํ–ˆ๋‹ค. ๊ทธ๋ž˜์„œ delegate ํŒจํ„ด์„ ์ด์šฉํ•ด์„œ manage ๋ทฐ๊ฐ€ ์‚ฌ๋ผ์งˆ๋•Œ, main ๋ทฐ์—์„œ ๋ผ๋ฒจ์˜ ๊ฐ’์ด ๋ณ€ํ™˜๋˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.

protocol delegate ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ฉด์„œ, ๊ฐ์ฒด์˜ ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถ”๊ธฐ ์œ„ํ•ด์„œ protocol์„ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

protocol Delegator: AnyObject {
    var stock: [Fruit: Int]? { get set }
    var delegate: Updateable? { get set }
}
private func setUpDelegate(_ viewNavigation: UINavigationController) {
    guard let topView = viewNavigation.topViewController as? Delegator else { return }
    topView.stock = juiceMaker.fruitStore.stock
    topView.delegate = self
}

private func moveManagingStockView() -> UINavigationController? {
    guard let managingStockVN = self.storyboard?.instantiateViewController(withIdentifier: "ManagingStockViewNavigation") as? UINavigationController else { return nil }
    self.present(managingStockVN, animated: true, completion: nil)
    return managingStockVN
}

๊ทธ๋ฆฌ๊ณ  ํ™”๋ฉด์„ ์ด๋™ ํ• ๋•Œ, ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ด๊ธฐ ์œ„ํ•ด์„œ ๋‹ค๋ฅธ Navigation Controller ๋ฅผ ์—ฐ๊ฒฐํ•ด๋„ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ์ง€ ์•Š๋„๋ก ๋‹ค์šด ์บ์ŠคํŒ…์„ ํ•  protocol ์„ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ–ˆ๋‹ค. (Delegator ๋ฅผ ์ฑ„ํƒํ•œ ๋ทฐ์ด๊ธฐ๋งŒ ํ•˜๋ฉด ํƒ‘๋ทฐ๋กœ ์–ด๋–ค ๋ทฐ๊ฐ€ ์™€๋„ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋‹ค.

auto Layout stack view ๋ฅผ ์ด์šฉํ•ด ์—ฐ๊ด€๋œ ์ด๋ฏธ์ง€, ๋ผ๋ฒจ ์Šคํ…ํผ๋ฅผ ๋ฌถ๊ณ  ๋˜ ๊ทธ๋Ÿฌํ•œ stack view ๋“ค์„ ํ•˜๋‚˜์˜ stack view ๋กœ ๋ฌถ์–ด์„œ auto Layout ์„ ์ ์šฉํ–ˆ๋‹ค.

About

๐Ÿป iOS ์ปค๋ฆฌ์–ด ์Šคํƒ€ํ„ฐ ์บ ํ”„ ๐Ÿงƒ ์ฅฌ์Šค ๋ฉ”์ด์ปค ํ”„๋กœ์ ํŠธ

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Swift 100.0%