๐ŸŽ iOS & Swift

[iOS] Associated Type

taeeekki 2021. 9. 5. 15:55

associated type์— ๊ด€ํ•˜์—ฌ

 

์•ˆ๋…•ํ•˜์„ธ์š”, ํƒœ๋ผ์ž…๋‹ˆ๋‹ค.
์ด๋ฒˆ ๊ธ€์€ ์ •๋ฆฌํ˜•ํƒœ๋กœ ์ž‘์„ฑํ•ด๋‘์–ด ์–ดํˆฌ๊ฐ€ ์กฐ๊ธˆ ๋”ฑ๋”ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.. ์ดํ•ด๋ถ€ํƒ๋“œ๋ ค์š” ๐Ÿฅฒ

์ด๋ฒˆ ๊ธ€์€ ์–ดํˆฌ๋„ ๋”ฑ๋”ฑํ•˜๊ณ  ์ค„๊ธ€ ํ˜•์‹์ด๋‹ค. ๋„ˆ๋ฌด ์–ด๋ ต๊ฒŒ ์ƒ๊ฐํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ๊ฐœ๋…์ด๋‹ค. ๋‹จ์ˆœํ•˜๊ฒŒ ๋งž์„œ๋ณด์ž.

 

์š”์•ฝ

  • ํ”„๋กœํ† ์ฝœ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์ œ๋„ค๋ฆญ Placeholder์˜ ๋А๋‚Œ์ด๋‹ค.
  • Associated Type์€ ์›๋ž˜ typealias์˜€๋Š”๋ฐ, Swift 2.2๋ถ€ํ„ฐ Associated Type์ด๋ž€ ํ‚ค์›Œ๋“œ๋กœ ๋ฐ”๋€Œ์—ˆ๋‹ค.

 

์„ค๋ช…

์œ„์˜ ๋‘ ๊ฐ€์ง€ ๊ด€์ ์—์„œ ๋ณด๋ฉด ๋‚ด์šฉ์€ ํฌ๊ฒŒ ์–ด๋ ต์ง€ ์•Š๋‹ค. ์•„๋ž˜์˜ ์˜ˆ์‹œ๋กœ ํ•จ๊ป˜ ์ดํ•ดํ•ด๋ณด๊ฒ ๋‹ค.

 

์šฐ์„  ํ”„๋กœ์ ํŠธ์— ๋Œ€ํ•ด ์ž ๊น ์ดํ•ดํ•ด๋ณด๋ฉด, ํ”„๋กœ์ ํŠธ๋Š” ํ˜„์žฌ MVVM ํŒจํ„ด์„ ๋”ฐ๋ฅด๊ณ  ์žˆ๋‹ค. ๋‹ค์Œ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๋Š” ViewModel์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. ๋ณดํ†ต ๊ฐ ViewController๋งˆ๋‹ค ๋Œ€์‘๋˜์–ด ๊ฐ๊ฐ์˜ ViewModel์„ ํ•˜๋‚˜์”ฉ ๊ตฌํ˜„ํ•˜๊ณ , ViewController๋Š” ViewModel์„ ์†์„ฑ์œผ๋กœ ๊ฐ€์ง€๊ฒŒ ๋œ๋‹ค.

 

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

 

ํ”„๋กœ์ ํŠธ์—์„œ ViewModel์ด๋ผ๋Š” ๊ฒƒ์„ ViewController๋งˆ๋‹ค ๊ฐ€์ง€๊ฒŒ ๋˜๊ณ , ViewModel๊ณผ View๋ฅผ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ์ž‘์—…์ธ bindViewModel()์„ ๊ณตํ†ต์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค. ์ด๋ ‡๊ฒŒ ๊ณตํ†ต๋˜๋Š” ์ž‘์—…์„ ์šฐ๋ฆฌ๋Š” ํ”„๋กœํ† ์ฝœ๋กœ ๋ฌถ์–ด์„œ ์ž‘์—…ํ•  ๊ฒƒ์ด๋‹ค.

 

ํ”„๋กœํ† ์ฝœ์—๋Š” ํ˜•ํƒœ๋งŒ ์žก์•„๋‘๊ฒŒ ๋œ๋‹ค. ์ง์ ‘ ๊ตฌํ˜„๊นŒ์ง€๋Š” ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ํ˜น์‹œ ์ด ๋ถ€๋ถ„์ด ์ดํ•ด๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ํ”„๋กœํ† ์ฝœ์— ๋Œ€ํ•ด์„œ ํ•œ ๋ฒˆ ์ดํ•ดํ•˜๊ณ  ์˜ค๋Š” ๊ฒƒ์ด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค. ๊ณ„์† ์ด์–ด๋‚˜๊ฐ€๋ฉด ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“ค ViewModelBindableType ํ”„๋กœํ† ์ฝœ์•ˆ์—๋Š” ๊ตฌํ˜„๋˜์–ด์•ผ ํ•  viewModel ํ”„๋กœํผํ‹ฐ์™€ bindViewModel ๋ฉ”์„œ๋“œ๊ฐ€ ์กด์žฌํ•œ๋‹ค.

 

๊ทธ๋Ÿฌ๋‚˜ ์ƒ๊ฐํ•ด ๋ณผ ํฌ์ธํŠธ๊ฐ€ ํ•˜๋‚˜ ์žˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ViewModel์„ ViewController์— ๋”ฐ๋ผ ๊ณ„์†ํ•ด์„œ ์ƒˆ๋กœ ๋งŒ๋“ค๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ ViewModel์˜ Type ์€ ๋ชจ๋‘ ๋‹ค๋ฅด๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ•˜์ง€? ์—ฌ๊ธฐ์„œ ์ข‹์€ ํ•ด๊ฒฐ์ฑ…์ด ํ•˜๋‚˜ ๋‚˜์˜จ๋‹ค. associatedType ์„ ์ด์šฉํ•˜๋ฉด ๋œ๋‹ค. ์ž„์˜๋กœ ํƒ€์ž…์„ ์ •ํ•ด๋‘์–ด์„œ viewModel์˜ ํƒ€์ž…์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์—ฌ๊ธฐ์„œ typealias์™€ generic ๊ฐœ๋…์ด ๋– ์˜ค๋ฅธ๋‹ค.

 

๋งŒ์•ฝ ํ”„๋กœํผํ‹ฐ์˜ ํƒ€์ž…์ด ๋™์ผํ•˜๋‹ค๋ฉด ์šฐ๋ฆฌ๋Š” ๊ทธ๋ƒฅ ์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค. ๊ณตํ†ต์ ์œผ๋กœ ์‚ฌ์šฉ๋  name์ด๋ผ๋Š” ํ”„๋กœํผํ‹ฐ๊ฐ€ ํ•ญ์ƒ String ํƒ€์ž…์ผ ๊ฒƒ์ด๋ผ๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•˜๋ฉด ๋  ๊ฒƒ์ด๋‹ค.

 

protocol ViewContainer {
	var name: String { get set }
}

 

๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๋Š” ํƒ€์ž…์ด ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ๋ฅผ ์ƒ๊ฐํ•ด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํƒ€์ž…์„ ์ž„์˜๋กœ ์ง€์ •ํ•ด์ค„ ๊ฒƒ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์‹ค์ œ๋กœ ViewController์—์„œ ViewModelBindableType์„ ์ฑ„ํƒํ•ด์„œ ์‚ฌ์šฉํ•  ๋•Œ์— viewModel์˜ ํƒ€์ž…์„ ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ํ˜•์‹(MemoListViewModel, MemoDetailViewModel ๋“ฑ)์œผ๋กœ ์ง€์ •ํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค.

 

// ViewModelBindableType.swift (ํ”„๋กœํ† ์ฝœ)

protocol ViewModelBindableType {
    associatedtype ViewModelType
    
    var viewModel: ViewModelType! { get set }
    func bindViewModel()
}

 

// MemoListViewController.swift (๋ทฐ ์ปจํŠธ๋กค๋Ÿฌ)

import UIKit

class MemoListViewController: UIViewController, ViewModelBindableType {
    
    var viewModel: MemoListViewModel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    func bindViewModel() {
        
    }
}
// MemoDetailViewController.swift (๋ทฐ ์ปจํŠธ๋กค๋Ÿฌ)

import UIKit

class MemoDetailViewController: UIViewController, ViewModelBindableType {

    var viewModel: MemoDetailViewModel!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }
    
    func bindViewModel() {
        
    }
}
// ์œ„์˜ ์žˆ๋Š” ์ฝ”๋“œ์— typealias๋ฅผ ์ถ”๊ฐ€ํ•œ ๊ฒƒ

import UIKit

class MemoDetailViewController: UIViewController, ViewModelBindableType {
    
    typealias ViewModelType = MemoDetailViewModel

    var viewModel: ViewModelType!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }
    
    func bindViewModel() {
        
    }
}

 

๋งˆ๋ฌด๋ฆฌ

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

 

๋ ˆํผ๋Ÿฐ์Šค

https://zeddios.tistory.com/382

https://woongsios.tistory.com/97