๋‹ค์–‘ํ•œ ์˜์กด์„ฑ ์ฃผ์ž… ๋ฐฉ๋ฒ•์„ ๊ณ ๋ คํ•˜๊ณ , ์ตœ์ข…์ ์œผ๋กœ ViewController์— ์ƒ์„ฑ์ž ์ฃผ์ž… ๋ฐฉ์‹์„ ํ†ตํ•ด ์ปดํŒŒ์ผ ํƒ€์ž„์— ์ฃผ์ž… ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ณ€๊ฒฝํ•˜์˜€์Šต๋‹ˆ๋‹ค.

  • ์ดˆ๊ธฐ์— ์ž‘์„ฑํ•œ ์˜์กด์„ฑ ์ฃผ์ž…์ด๋ผ๊ณ  ์ฐฉ๊ฐํ•œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.
  • ๋‚ด๋ถ€์—์„œ ์ƒ์„ฑ์„ ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋ถ„๋ฆฌํ•œ ์ด์œ ๊ฐ€ ์ „ํ˜€ ์—†๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

  • ๋ฉ”์†Œ๋“œ๋กœ ํ•ด๋‹น ๋‚ด๋ถ€ ํ”„๋กœํผํ‹ฐ์— ์ฃผ์ž…ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ํ•˜์ง€๋งŒ ์—ฌ์ „ํžˆ ํ•ด๋‹น ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋Š”์ง€ ์ปดํŒŒ์ผ ํƒ€์ž„์— ํ™•์ธํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ์ด์— ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์ฃผ์ž…ํ•˜๋Š” ๋ฐฉ์‹์„ ์‹œ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ํ•˜์ง€๋งŒ, ์‚ฌ์šฉํ•˜๋Š” ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๊ฐ€, ๋‹จ์ˆœ ์ƒ์„ฑ์„ ํ–ˆ์„ ์‹œ, ๋ทฐ๋ชจ๋ธ ์ฃผ์ž…์ด ํ•„์ˆ˜์ ์ธ์ง€ ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • ์ด๋ฅผ fatal error๋กœ ๋ง‰์•˜์œผ๋‚˜, ์—ฌ์ „ํžˆ ์ปดํŒŒ์ผ ํƒ€์ž„์— ์•Œ ์ˆ˜ ์—†๋‹ค๋Š” ์ ์€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

  • ์ตœ์ข…์ ์œผ๋กœ, Coder๋ฅผ ํ†ตํ•ด ์ƒ์„ฑํ•˜๋Š” ๊ฒฝ์šฐ ์ž์ฒด๋ฅผ ์ปดํŒŒ์ผ ํƒ€์ž„์— ๋ง‰๊ธฐ ์œ„ํ•ด available ํƒœ๊ทธ๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ๊ฒฐ๊ณผ์ ์œผ๋กœ, DIViewController๋ผ๋Š” ์š”์†Œ๋ฅผ ๋งŒ๋“ค๊ณ , ViewModel์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ํ•ด๋‹น VC๋ฅผ ์ƒ์†ํ•˜์—ฌ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ์ œ๋„ค๋ฆญ์„ ์‚ฌ์šฉํ•˜์—ฌ ์–ด๋–ค ํƒ€์ž…์ด๋“  ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • ์Šคํ† ๋ฆฌ ๋ณด๋“œ๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ, iOS13 ์ดํ›„ ๋ถ€ํ„ฐ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
import UIKit
 
class DefaultDIViewController<T>: DefaultViewController {
    var viewModel: T
 
    init(viewModel: T) {
        self.viewModel = viewModel
        super.init(nibName: nil, bundle: nil) // code๋กœ VC๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒฝ์šฐ nib, bundle ๋ชจ๋‘ ๋ถˆํ•„์š”
    }
 
    init?(coder: NSCoder, viewModel: T) {
        self.viewModel = viewModel
        super.init(coder: coder)
    }
 
    @available(*, unavailable, renamed: "init(coder:viewModel:)")
    required init?(coder: NSCoder) {
        fatalError("Invalid way of decoding this ViewController")
    }
}
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewModel = storyboard.instantiateInitialViewController { coder -> RoomListViewController in
    let viewModel = DefaultRoomListViewModel(usecase: RoomListUseCase(repository: RoomListRepository(service: FirebaseService.shared)))
    return .init(coder: coder, viewModel: viewModel) ?? RoomListViewController(viewModel: viewModel)
}
  • ๊ฒฐ๊ณผ์ ์œผ๋กœ, ViewController๋ฅผ ์ƒ์„ฑ ์‹œ์ ์— ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ•˜๋Š” ๋ฐฉ์‹์„ ๋„์ž…ํ•˜์—ฌ, ์ปดํŒŒ์ผ ํƒ€์ž„์— ์ฃผ์ž… ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ณ€๊ฒฝํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์˜์กด์„ฑ ์ฃผ์ž…์˜ ๋ฐฉ๋ฒ•๊ณผ ์˜์‚ฌ๊ฒฐ์ • ๊ณผ์ •

  • ์˜์กด์„ฑ ์ฃผ์ž…์˜ ๋ฐฉ์‹์—๋Š” ํฌ๊ฒŒ 4๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค.
  • ํ”„๋กœํผํ‹ฐ ์ฃผ์ž… & ๋ฉ”์„œ๋“œ ์ฃผ์ž…
    • ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ, ํ˜น์€ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ ์šฉํ•ด์„œ ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.
  • ์ƒ์„ฑ์ž ์ฃผ์ž…
    • ์ƒ์„ฑ์ž๋งŒ ๋ณด๊ณ  ์˜์กด์„ฑ์„ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.
    • A์™€ B๊ฐ€ ์„œ๋กœ ์•Œ์•„์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
    • ์ด๋Ÿด ๊ฒฝ์šฐ ์ƒ์„ฑ์ž ์ฃผ์ž… ๋ฐฉ์‹์œผ๋กœ ์„œ๋กœ์˜ ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•˜๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜์—ฌ, ๋ฉ”์„œ๋“œ ํ˜น์€ ํ”„๋กœํผํ‹ฐ ์ฃผ์ž… ๋ฐฉ์‹์„ ์“ฐ๋Š” ๊ฒƒ์ด ๋ณด๋‹ค ๊น”๋”ํ•œ ๋ฐฉ๋ฒ•์ผ ์ˆ˜ ์žˆ๋‹ค.
    • ๊ฐ€์žฅ ๊น”๋”ํ•œ ๋ฐฉ์‹์ด๋‚˜ ๊นŒ๋‹ค๋กœ์šธ ์ˆ˜ ์žˆ๋‹ค.
  • ์„œ๋น„์Šค ๋กœ์ผ€์ดํ„ฐ ํŒจํ„ด (์•ˆํ‹ฐ ํŒจํ„ด)
    • ๋ชจ๋“  ์˜์กด์„ฑ์„ ์•Œ๊ณ  ์žˆ๋Š” locator ๊ฐ์ฒด๊ฐ€ ์žˆ๊ณ , ์ด ํ•ด๋‹น ๊ฐ์ฒด์— ์š”์ฒญํ•˜์—ฌ ์˜์กด์„ฑ์„ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.
      • ์ƒ์„ฑ์ž๋งŒ ๋ณด๊ณ , ์˜์กด์„ฑ์„ ํŒŒ์•…ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.
      • ๋˜ํ•œ locator ์ž์ฒด์— ์˜์กดํ•˜๊ฒŒ ๋œ๋‹ค.
      • ํ•ด๋‹น ํด๋ž˜์Šค์—์„œ ์š”์ฒญ์„ ํ•˜๋Š” ํ˜•ํƒœ์ด๊ธฐ ๋•Œ๋ฌธ์— ์™ธ๋ถ€์—์„œ mock ๊ฐ์ฒด๋ฅผ ๊ฐˆ์•„๋ผ์›Œ ๋„ฃ์–ด์„œ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅํ•ด ์กŒ๋‹ค.
      • ๋”ฐ๋ผ์„œ ์•ˆํ‹ฐ ํŒจํ„ด์ด๋‹ค.

์ด์ค‘, ์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์˜ ๊ฒฝ์šฐ ์„œ๋กœ ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ด ๋ฐœ๊ฒฌ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ์ƒ์„ฑ์ž ์ฃผ์ž… ๋ฐฉ์‹์„ ๋„์ž…ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ํ•ฉ๋ฆฌ์ ์ธ ํŒ๋‹จ์ด๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค.