๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐ŸŽ iOS/Architecture

[Design Pattern] MVCํŒจํ„ด์ด๋ž€? (Model-View-Controller)

by Fomagran ๐Ÿ’ป 2021. 6. 3.
728x90
๋ฐ˜์‘ํ˜•

์•ˆ๋…•ํ•˜์„ธ์š” Foma ์ž…๋‹ˆ๋‹ค!

 

์˜ค๋Š˜ ์•Œ์•„๋ณผ ์ฃผ์ œ๋Š” ํ”ํžˆ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ๋””์ž์ธ ํŒจํ„ด์ธ Model - View -Controller ์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๋ฐ”๋กœ ์‹œ์ž‘ํ• ๊ฒŒ์š”!


MVC ํŒจํ„ด์ด๋ž€?

 

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

 

์žฅ์ 

 

๋‹ค๋ฅธ ํŒจํ„ด์— ๋น„ํ•ด ๊ตฌ์กฐ๋ฅผ ๋น„๊ต์  ์‰ฝ๊ฒŒ ์„ค๊ณ„ํ•  ์ˆ˜ ์žˆ์–ด

 

๊ทœ๋ชจ๊ฐ€ ์ž‘์€ ํ”„๋กœ์ ํŠธ ์ง„ํ–‰ ์‹œ ๋น ๋ฅด๊ฒŒ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋˜ํ•œ ๋ณดํ†ต ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์นœ์ˆ™ํ•œ ๊ตฌ์กฐ์ด๊ธฐ ๋•Œ๋ฌธ์— ์‰ฝ๊ฒŒ ํ˜‘์—…์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

 

๋‹จ์ 

 

๋ชจ๋ธ์€ ๋ทฐ์˜ ์ธํ„ฐ๋ž™์…˜์— ๋”ฐ๋ผ์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ”๋€Œ๊ณ  ๋ทฐ๋Š” ๋ชจ๋ธ์˜ ๋ฐ”๋€ ๋ฐ์ดํ„ฐ์— ์˜ํ•ด ์—…๋ฐ์ดํŠธ ๋˜๊ธฐ ๋•Œ๋ฌธ์—

 

์„œ๋กœ ์™„๋ฒฝํ•œ ๋ถ„๋ฆฌ๊ฐ€ ์–ด๋ ต๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

ํŠนํžˆ iOS์˜ ๊ฒฝ์šฐ View์˜ ๋ผ์ดํ”„ ์‚ฌ์ดํด์„ Controller์—์„œ ๊ด€๋ฆฌํ•˜์—ฌ ๊ฐ•ํ•˜๊ฒŒ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

๊ณ ๋กœ ๋ทฐ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ๋ทฐ์—์„œ ํ•˜๋Š” ์—ญํ• ๊ณผ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ํ•˜๋Š” ์—ญํ• ์„ ๋ชจ๋‘ ๋‹ค ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋˜์–ด ๋ทฐ์ปจํŠธ๋กค๋Ÿฌ ๋‚ด ์ฝ”๋“œ๊ฐ€

 

๋ณต์žกํ•ด์ง€๊ณ  ์ด๋Š” ์œ ์ง€๋ณด์ˆ˜์˜ ์–ด๋ ค์›€์„ ๊ฐ€์ ธ์˜จ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

 


View

 

๋ทฐ๋Š” ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ๊ฐ’์— ๋”ฐ๋ผ ํ™”๋ฉด์„ ์ถœ๋ ฅํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

 

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

 

์ „๋‹ฌํ•˜๊ณ  ์ปจํŠธ๋กค๋Ÿฌ๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ๋ฐ›์•„ ํ™”๋ฉด์„ ์—…๋ฐ์ดํŠธ ํ•ฉ๋‹ˆ๋‹ค.

 

์•„๋ž˜์™€ ์˜ˆ์ œ ํ™”๋ฉด์œผ๋กœ ์„ค๋ช…ํ•˜๋ฉด ์ด์ „ ๋ฒ„ํŠผ๊ณผ ๋‹ค์Œ ๋ฒ„ํŠผ์ด ๋ˆŒ๋ฆฐ ๊ฒƒ์„ ์ปจํŠธ๋กค๋Ÿฌ์—๊ฒŒ ์•Œ๋ ค์ฃผ๊ณ 

 

์ปจํŠธ๋กค๋Ÿฌ๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ์บ๋ฆญํ„ฐ ๋ชจ๋ธ์„ ํ™”๋ฉด์— ์ถœ๋ ฅํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

 

์ฝ”๋“œ๋กœ ์ž‘์„ฑํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

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

import UIKit

class CharacterView: UIView {

    //ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•˜๊ณ  ์žˆ๋Š” ์š”์†Œ๋“ค
    @IBOutlet weak var image:UIImageView! //์ด๋ฏธ์ง€
    @IBOutlet weak var gender:UILabel! //์„ฑ๋ณ„
    @IBOutlet weak var name:UILabel! //์ด๋ฆ„
    @IBOutlet weak var country:UILabel! //๊ตญ๊ฐ€
    @IBOutlet weak var nextButton:UIButton! //๋‹ค์Œ ๋ฒ„ํŠผ
    @IBOutlet weak var previousButton:UIButton! //์ด์ „ ๋ฒ„ํŠผ
    
    //์ปจํŠธ๋กค๋Ÿฌ๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ์บ๋ฆญํ„ฐ๋กœ ์—…๋ฐ์ดํŠธ ํ•จ.
    func updateView(character:Character) {
        self.image.image = character.image
        self.gender.text = character.gender
        self.name.text = character.name
        self.country.text = character.country
    }
    
}

Model

 

๋ชจ๋ธ์„ ๋ทฐ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

 

์ด๋ฏธ์ง€๊ฐ€ ์–ด๋–ค ์ด๋ฏธ์ง€์ธ์ง€, ํฌ๊ธฐ, ํ…์ŠคํŠธ ์ž์ฒด, ํฐํŠธ, ๊ตต๊ธฐ ๋“ฑ ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•˜๊ณ  ์žˆ๋Š”

 

๋ชจ๋“  ์š”์†Œ๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋ทฐ์—์„œ ์‚ฌ์šฉ์ž์˜ ์ธํ„ฐ๋ž™์…˜์ด ๋ฐœ์ƒํ•˜๋ฉด ๋ชจ๋ธ์€ ์ปจํŠธ๋กค๋Ÿฌ๋กœ๋ถ€ํ„ฐ ์ธํ„ฐ๋ž™์…˜์— ๋งž๋Š” ๋ฐ์ดํ„ฐ๋กœ ์—…๋ฐ์ดํŠธ ํ•˜๋ผ๊ณ  ์ง€์‹œ๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค.

 

๋ชจ๋ธ์€ ์•Œ๋งž์€ ๋ฐ์ดํ„ฐ๋กœ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ์ปจํŠธ๋กค๋Ÿฌ์—๊ฒŒ ์•Œ๋ ค์ค๋‹ˆ๋‹ค.

 

์˜ˆ์ œ ํ™”๋ฉด์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

์ฝ”๋“œ๋กœ ์„ค๋ช…ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์บ๋ฆญํ„ฐ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐ์ดํ„ฐ์™€ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

import UIKit

struct Character {
    
    //ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•  ๋ฐ์ดํ„ฐ
    let image:UIImage
    let name:String
    let gender:String
    let country:String
    
    //์ดˆ๊ธฐํ™”
    init(name:String,image:UIImage,gender:String,country:String,previousButtonText:String,nextButtonText:String) {
        self.name = name
        self.image = image
        self.gender = gender
        self.country = country
    }
}

Controller

 

์ปจํŠธ๋กค๋Ÿฌ๋Š” ๋ทฐ์™€ ๋ชจ๋ธ์˜ ๋‹ค๋ฆฌ ์—ญํ• ์„ ํ•˜๋ฉฐ 

 

๋ทฐ๋กœ๋ถ€ํ„ฐ ์‚ฌ์šฉ์ž์˜ ์ธํ„ฐ๋ž™์…˜์„ ๋ฐ›์•„ ๋ชจ๋ธ์— ์ „๋‹ฌํ•˜๊ณ 

 

๋ฐ”๋€ ๋ชจ๋ธ ๋ฐ์ดํ„ฐ๋ฅผ ๋ทฐ์— ๋‹ค์‹œ ์ „๋‹ฌํ•˜์—ฌ ์—…๋ฐ์ดํŠธ ํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

 

์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

import UIKit

class CharacterController: UIViewController {
    
    //์ „์ฒด ๋ชจ๋ธ ๋ฐ์ดํ„ฐ
    let characters:[Character] = [
        Character(name:"์Šคํฐ์ง€๋ฐฅ",image: #imageLiteral(resourceName: "แ„‰แ…ณแ„‘แ…ฉแ†ซแ„Œแ…ตแ„‡แ…กแ†ธ"), gender: "๋‚จ์ž", country:"๋ฏธ๊ตญ"),
        Character(name:"๋šฑ์ด",image: #imageLiteral(resourceName: "แ„„แ…ฎแ†ผแ„‹แ…ต"), gender: "๋‚จ์ž", country:"๋ฏธ๊ตญ"),
        Character(name:"์ง•์ง•์ด",image: #imageLiteral(resourceName: "แ„Œแ…ตแ†ผแ„Œแ…ตแ†ผแ„‹แ…ต"), gender: "๋‚จ์ž", country:"๋ฏธ๊ตญ"),
        Character(name:"ํ”Œ๋žญํฌํ†ค",image: #imageLiteral(resourceName: "แ„‘แ…ณแ†ฏแ„…แ…กแ†ผแ„แ…ณแ„แ…ฉแ†ซ"), gender: "๋‚จ์ž", country:"๋ฏธ๊ตญ"),
        Character(name:"ํํ์—ฌ์‚ฌ",image: #imageLiteral(resourceName: "แ„‘แ…ฉแ†ผแ„‘แ…ฉแ†ผแ„‡แ…ฎแ„‹แ…ตแ†ซ"), gender: "์—ฌ์ž", country:"๋ฏธ๊ตญ")
    ]
    //์บ๋ฆญํ„ฐ๋ทฐ
    @IBOutlet weak var characterView: CharacterView!
    //ํ˜„์žฌ ์ธ๋ฑ์Šค
    var index:Int = 0
    //ํ˜„์žฌ ๋ชจ๋ธ ๋ฐ์ดํ„ฐ
    var character:Character!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        configure()
        notifyFromView()
    }
    
    //๋ชจ๋ธ๊ณผ ๋ทฐ ์ดˆ๊ธฐํ™”
    func configure() {
        character = characters[index]
        updateView()
    }
    //๋ทฐ๋กœ๋ถ€ํ„ฐ ์ด์ „๋ฒ„ํŠผ๊ณผ ๋‹ค์Œ๋ฒ„ํŠผ์— ์ธํ„ฐ๋ž™์…˜์„ ์ „๋‹ฌ๋ฐ›์Œ
    func notifyFromView() {
        characterView.nextButton.addTarget(self, action: #selector(nextButtonTapped(_:)), for: .touchUpInside)
        characterView.previousButton.addTarget(self, action: #selector(previousButtonTapped(_:)), for: .touchUpInside)
    }
    //๋‹ค์Œ๋ฒ„ํŠผ์ด ๋ˆŒ๋ ธ๋‹ค๋ฉด
    @objc func nextButtonTapped(_ sender: UIButton) {
        //๋‹ค์Œ ์ธ๋ฑ์Šค๋กœ ๋ณ€๊ฒฝ
        if index < 4 {
            index += 1
        }
        //๋ทฐ ์—…๋ฐ์ดํŠธ
        updateView()
    }
    //์ด์ „ ๋ฒ„ํŠผ์ด ๋ˆŒ๋ ธ๋‹ค๋ฉด
    @objc func previousButtonTapped(_ sender: UIButton) {
        //์ด์ „ ์ธ๋ฑ์Šค๋กœ ๋ณ€๊ฒฝ
        if index > 0 {
            index -= 1
        }
        //๋ทฐ ์—…๋ฐ์ดํŠธ
        updateView()
    }
    //๋ทฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋ผ๊ณ  ์ง€์‹œ
    @objc func updateView() {
        //์บ๋ฆญํ„ฐ ๋ทฐ์˜ ์บ๋ฆญํ„ฐ๋ฅผ ํ˜„์žฌ ์บ๋ฆญํ„ฐ๋กœ ๋ฐ”๊ฟˆ.
        characterView.updateView(character: characters[index])
    }
}

 

์•„๋ž˜์™€ ๊ฐ™์ด ๋ทฐ์—์„œ ๋ฐ›์€ ์‚ฌ์šฉ์ž ์ธํ„ฐ๋ž™์…˜์— ๋”ฐ๋ผ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ”๋€Œ๊ณ  ๋ฐ”๋€ ๋ฐ์ดํ„ฐ์— ๋”ฐ๋ผ์„œ

 

๋ทฐ๊ฐ€ ์—…๋ฐ์ดํŠธ ๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

728x90
๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€