Published on

๐ŸŽ Swift - MVVM, Clean Architecture.01

Authors
  • avatar
    Name
    ์ด์ฐฝ์ค€
    Twitter

RxSwift๋ฅผ ๋‹ค๋ฃจ๊ฒŒ ๋˜๋‹ค ๋ณด๋‹ˆ ๋ถˆ๊ฐ€ํ•ญ๋ ฅ์ ์œผ๋กœ ๋ˆˆ์— ๊ณ„์† ๋ณด์ด๋Š” MVVM ๊ตฌ์กฐ๋ผ๋Š” ๋†ˆ์ด ์žˆ์Šต๋‹ˆ๋‹ค. View Controller์˜ ์—ญํ• ์ด ๋„ˆ๋ฌด ๋ฌด๊ฑฐ์›Œ์ง€๊ณ  ์žˆ๋˜ ๊ฒƒ์„ ์ฒด๊ฐํ•˜๋˜ ์ค‘์ด์—ฌ์„œ ํ”„๋กœ์ ํŠธ๊ฐ€ ๋” ์ง„ํ–‰๋˜๊ธฐ ์ „์— MVVM ๊ตฌ์กฐ๋ฅผ ์ ์šฉํ•ด๋ณด๊ธฐ๋กœ ํ–ˆ์Šต๋‹ˆ๋‹ค.

์›๋ž˜๋Š” AWS ์„œ๋น„์Šค๋“ค์„ ์‚ฌ์šฉํ•ด๋ณด๊ณ ์ž ์‹œ์ž‘ํ–ˆ๋˜ ํ”„๋กœ์ ํŠธ์ธ๋ฐ ํ•˜๋‹ค๋ณด๋‹ˆ ์ด๊ฒƒ์ €๊ฒƒ ๋งŽ์ด ๊ฑด๋“ค์—ฌ๋ณด๊ฒŒ ๋˜๋„ค์š” ๐Ÿง

MVVM

MVVM ๊ตฌ์กฐ๋Š” ์‚ฌ์‹ค ๊ตณ์ด RxSwift๊ฐ€ ์•„๋‹ˆ์—ฌ๋„ iOS ์•ฑ๊ฐœ๋ฐœ์„ ๊ณต๋ถ€ํ•˜๋‹ค๋ณด๋ฉด ์ž์ฃผ ๋งˆ์ฃผ์น˜๊ฒŒ ๋˜๋Š” ์šฉ์–ด์ž…๋‹ˆ๋‹ค. MVVM์€ Model, View, View Model๋กœ ์ฝ”๋“œ๋ฅผ ๊ตฌ๋ถ„ํ•˜๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ๊ธฐ์กด์˜ MVC ๊ตฌ์กฐ์—์„œ ๋ญ”๊ฐ€๊ฐ€ ๋ถˆํŽธํ–ˆ์œผ๋‹ˆ๊นŒ ์ด๋Ÿฐ ์ƒˆ๋กœ์šด ๊ตฌ์กฐ๋ฅผ ์ ์šฉํ•˜๋Š” ๊ฒƒ์ด๊ฒ ์ฃ ? MVC ๊ตฌ์กฐ๋Š” ์ดํ•ดํ•˜๊ธฐ ์ƒ๋‹นํžˆ ์‰ฝ๊ณ  ์• ํ”Œ๋„ XCode์˜ ๊ธฐ๋ณธ ๊ตฌ์กฐ๋ฅผ MVC๋กœ ์„ค์ •ํ•ด๋‘” ๋“ฏ ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์œผ๋กœ ์„ค์ •๋œ ํŒŒ์ผ์˜ ์ด๋ฆ„์กฐ์ฐจ View Controller์ด๊ธฐ ๋•Œ๋ฌธ์ด์ฃ . ํ•˜์ง€๋งŒ MVC ๊ตฌ์กฐ๋Š” View Controller์—๊ฒŒ ๊ฑฐ์˜ ๋ชจ๋“  ๊ฒƒ์„ ๋งก๊น๋‹ˆ๋‹ค. ์•„๋ฌด๋ฆฌ class๋ฅผ ๋ถ„๋ฆฌํ•˜๋”๋ผ๋„ ๊ฒฐ๊ตญ์—๋Š” View Controller์—์„œ ์ฐธ์กฐํ•˜์—ฌ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜์ฃ .

MVVM ๊ตฌ์กฐ๋Š” View Controller๊ฐ€ ๋…๋ฐ•์“ฐ๋˜ ๊ตฌ์กฐ๋ฅผ ์„ธ๊ฐ€์ง€ ๊ตฌ์กฐ๋กœ ๋‚˜๋ˆ•๋‹ˆ๋‹ค.

MVVM Pattern

View & View Controller: ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค.

View Model: ํ™”๋ฉด์œผ๋กœ ์ „๋‹ฌ๋˜๋Š” ์ •๋ณด๋“ค๊ณผ ๊ทธ์— ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋“ค์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค.

Model: ์‹ค์งˆ์ ์ธ ๋ฐ์ดํ„ฐ๋“ค์˜ ์ €์žฅ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค.

View Model์€ Model์˜ ๋ฐ์ดํ„ฐ๋“ค์„ ๊ณ„์†ํ•ด์„œ Updateํ•ด์ฃผ๊ณ , View Controller์—๋Š” ํ™”๋ฉด์— ์ถœ๋ ฅํ•  ์ •๋ณด๋ฅผ ๋ฟŒ๋ ค์ค๋‹ˆ๋‹ค.

View Controller๋Š” View๋ฅผ ๊ตฌ์„ฑํ•ด์„œ ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ํ•ด์„œ ์–ป๋Š” ์ด์ ์ด ๋ญ๋ƒ?! ํ•˜์‹œ๋ฉด

์ด์ œ View Controller์™€ View์—๋Š” ์˜ค์ง ํ™”๋ฉด ๊ตฌ์„ฑ ์ฝ”๋“œ๋งŒ์ด ๋‚จ๊ฒจ์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์‹ค์งˆ์ ์ธ ๋™์ž‘ ์ฝ”๋“œ๋“ค์€ ์ „๋ถ€ View Model์— ๋“ค์–ด๊ฐ€๊ฒŒ ๋จ์œผ๋กœ์„œ UI์— ๋Œ€ํ•œ ์ ‘๊ทผ ์—†์ด๋„ ์ด๋Ÿฐ์ €๋Ÿฐ ํ…Œ์ŠคํŠธ๋‚˜ ๊ธฐ๋Šฅ ์ˆ˜์ •๋“ฑ์„ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ •๋ˆ๋œ ํŒŒ์ผ์€ ๋ค์ด๊ณ ์š”!

ํ•˜์ง€๋งŒ ๊ทธ๋ ‡๋‹ค๊ณ  MVVM ๊ตฌ์กฐ๊ฐ€ ๋งŒ๋Šฅ์ธ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค..

๊ณ ํ†ต๋ฐ›๋Š” View Model

View Controller๋Š” ์ด์ œ ๋ฌด๊ฒŒ๋ฅผ ์ข€ ๋œ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ชจ๋“  ์—…๋ฌด๋ฅผ ๋– ์•ˆ๊ฒŒ ๋œ View Modelโ€ฆ ์‚ฌ์‹ค์ƒ ๋ฌด๊ฒ๊ณ  ๊ณ„์†ํ•ด์„œ ์ถ”๊ฐ€๊ฐ€ ๋˜๋Š” ์ฝ”๋“œ๋“ค์€ ์ด View Model์ด ์ „๋ถ€ ๋งก๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ Clean-Architecture๋กœ View Model์˜ ๊ธฐ๋Šฅ๋“ค๋„ ์ชผ๊ฐœ๋ด…์‹œ๋‹ค!

Clean Architecture

Clean Architecture

์ด ๊ทธ๋ž˜ํ”„ ํ•˜๋‚˜๋กœ ๋ชจ๋“  ๊ฒƒ์„ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ข…์†์„ฑ์€ ์•ˆ์ชฝ์œผ๋กœ๋งŒ ํ–ฅํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์•ˆ์ชฝ์˜ ์š”์†Œ๋Š” ๋ฐ”๊นฅ์ชฝ ์š”์†Œ์— ๋Œ€ํ•ด ์•„๋ฌด๊ฒƒ๋„ ์•Œ ์ˆ˜ ์—†๋‹ค.
  • ๋ฐ”๊นฅ์ชฝ์—์„œ ์‚ฌ์šฉ๋œ ์ด๋ฆ„๋“ค์€ ์•ˆ์ชฝ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. (๋ณ€์ˆ˜, ํ•จ์ˆ˜, ํด๋ž˜์Šค ๋“ฑ)

์‚ฌ์‹ค ์„ธ๊ฐ€์ง€ ๋ชจ๋‘ ๋™์ผํ•œ ๋ง์„ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ”๊นฅ์ชฝ ์š”์†Œ๋“ค์€ ์–ด๋–ค ์ผ์ด ์žˆ์–ด๋„ ์ ˆ๋Œ€๋กœ ์•ˆ์ชฝ ์š”์†Œ๋“ค๋กœ๋ถ€ํ„ฐ์˜ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋„๋ก ํ•œ๋‹ค๋Š” ๊ฒƒ์ด์ฃ .

์ž ์ด์ œ ๊ฐ ๋‹จ๊ณ„๋ณ„๋กœ ์–ด๋–ค ์š”์†Œ๋“ค์ด ์žˆ๋Š”์ง€ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Entities (Model)

์ด ์•ˆ์— ์žˆ๋Š” ์š”์†Œ๋“ค์˜ ํŠน์ง•์€ ๊ฑฐ์˜ ๋ณ€๊ฒฝ๋  ์ผ์ด ์—†๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด DB์˜ ๊ตฌ์กฐ..๊ฐ™์€ ๊ฒƒ์ด ์žˆ๊ฒ ์ฃ ? ๊ทธ๋ž˜์„œ MVC ๋ชจ๋ธ์—์„œ Model๋กœ ์“ฐ๋˜ ๋ฐ์ดํ„ฐ์˜ ๊ตฌ์กฐ ํŒŒ์ผ ๋“ฑ์ด ์—ฌ๊ธฐ์— ์†ํ•ฉ๋‹ˆ๋‹ค.

struct Film {
  let id: Int
  let name: String
  let plot: String?
  let image: String?
}

์œ„์™€ ๊ฐ™์ด Film์ด๋ผ๋Š” ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋Š” ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ์ถ”๊ฐ€/์ˆ˜์ •ํ•  ๊ฒƒ์ด ์•„๋‹ˆ๋ผ๋ฉด ๊ฑฐ์˜ ๊ฑด๋“œ๋ฆด ์ผ์ด ์—†๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ์˜ํ™” ์ •๋ณด์•ฑ์˜ ๊ธฐ๋Šฅ์ด ์•„๋ฌด๋ฆฌ ๋ฐ”๋€Œ๋”๋ผ๋„ ์˜ํ™” ์ •๋ณด๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ์ผ์€ ์—†๊ฒ ์ฃ ?

Use Cases

Use Cases๋ž€ ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ โ€œ์‚ฌ์šฉโ€ํ•˜๋Š” ์•ฑ์˜ ๋™์ž‘๊ณผ ์‹œ๋‚˜๋ฆฌ์˜ค๋“ค์ด๋ผ๊ณ  ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ตฌ์กฐ๋ฅผ ์ฒ˜์Œ ๋ณด๋Š” ์ €์—๊ฒŒ๋Š” ๊ฐ€์žฅ ์ดํ•ดํ•˜๊ธฐ ํž˜๋“ค์—ˆ๋˜ ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค. ์ด๋ฒˆ์—๋„ ์‰ฝ๊ฒŒ ์œ„์˜ ์˜ˆ์‹œ๋ฅผ ํ†ตํ•ด ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์˜ํ™” ์ •๋ณด์•ฑ์„ ์ผœ๊ณ  ์‚ฌ์šฉ์ž๋Š” ์–ด๋–ค ํ–‰๋™์„ ํ• ๊นŒ์š”? ๊ฒ€์ƒ‰์„ ํ•˜๋˜, ์ถ”์ฒœ ์ •๋ณด๋ฅผ ๋ณด๋˜ ์˜ํ™” ์ •๋ณด๋ฅผ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•œ ์ผ์ข…์˜ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๊ฒ ์ฃ ? ์ด ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ๋ฐ”๋กœ Use Case์ž…๋‹ˆ๋‹ค.

var isLoginAccepted = BehaviorSubject(value: false)
func loadFilmInfo() {}
func updateFilmInfo() {}
func notifyReceived() {}

๋ณดํ†ต ์œ„์™€ ๊ฐ™์ด ํ‘œํ˜„๋ฉ๋‹ˆ๋‹ค. ์œ ์ €์˜ ํ–‰๋™, ์ƒํƒœ์˜ ๋ณ€ํ™” ๋“ฑ์œผ๋กœ ์ธํ•ด ์–ด๋–ค ์ถœ๋ ฅ๊ฐ’์˜ ๋ณ€ํ™”๊ฐ€ ํ•„์š”ํ•  ๋•Œ Use Cases๊ฐ€ ์ถœ๋™ํ•˜์—ฌ ํ•ด๊ฒฐํ•ด์ค€๋‹ค ๊ณ  ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Interface Adapters

์ด ๋ถ€๋ถ„์€ Presentation Layer๋ผ๊ณ  ๋ถ€๋ฅด๋Š” ์‚ฌ๋žŒ๋“ค๋„ ๋งŽ์Šต๋‹ˆ๋‹ค. ์–ด๋Š์ชฝ์ด๋˜ ์ด๋ฆ„์—์„œ ํ™”๋ฉด์˜ ๊ตฌ์„ฑ๊ณผ ๊ด€๋ จ์ด ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค๋Š” ๋Š๋‚Œ์ด ๋“ค์ฃ ?

MVVM ๋ชจ๋ธ์˜ View Model์ด ๋ณดํ†ต ์ด ๊ตฌ์—ญ์— ํ•ด๋‹น๋ฉ๋‹ˆ๋‹ค. Clean Architecture๋ฅผ ์ ์šฉํ•œ MVVM ๊ตฌ์กฐ์—์„œ View Model์€ ์˜ค์ง ํ™”๋ฉด์— ์ถœ๋ ฅ๋  ๋ฐ์ดํ„ฐ๋ฅผ ์ตœ์ข…์ ์œผ๋กœ ๊ฐ€๊ณตํ•˜๋Š” ์—ญํ• ๋งŒ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

func setTimestampFormat() {}
func setFilmGradeFormat() {}

๊ทธ๋ž˜์„œ ๋ณดํ†ต ์œ„์™€ ๊ฐ™์ด Use Cases์˜ output์œผ๋กœ ์–ป์€ ์ •๋ณด๋ฅผ ์‚ฌ์šฉ์ž๊ฐ€ ๋ณด๊ธฐ ์‰ฝ๊ฒŒ ๊ฐ€๊ณตํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋งŽ์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

20220323 โžก๏ธ 2022๋…„ 3์›” 23์ผ

์ฒ˜๋Ÿผ์š”.

Frameworkds & Drivers

์ด ๋ถ€๋ถ„์€ ์ตœ์™ธ๊ณฝ์ธ ๋งŒํผ ๊ฐ€์žฅ ํ™œ๋ฐœํ•˜๊ฒŒ ๋ณ€ํ˜•์ด ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘์ ์œผ๋กœ ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š” UI๋‚˜ DB ์™ธ์—๋„ Framework๋“ฑ๋„ ์—ฌ๊ธฐ์— ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.