본문 바로가기
Xcode/Swift - PlayGround

PlayGround ) Design Pattern (MVC)

by 후르륵짭짭 2020. 10. 2.
728x90
반응형

안녕하세요 후르륵짭짭 입니다!

오늘은 디자인 패턴에 대해서 알아보려고 합니다.

제가 디자인 패턴에 대해 처음 알게된 것은 "소프트웨어 공학" 수업을 듣고 나서 입니다.

이때 처음으로 MVC 패턴을 알게 됐고, 그 당시는 제가 Swift를 할 줄 몰라서 JAVA로 GUI랑 함께 

MVC 패턴을 구현 했던게 기억 납니다.

 

** 디자인 패턴을 왜 알아야 하나 **

사실 혼자서 이거나 단순한 개발 이라면 디자인 패턴을 알 필요는 없습니다.

하지만 우리가 할 것은 멋진 앱이고, 다른 사람과 협업을 언젠가는 하게 될 앱을 개발 해야하기 때문에

남을 위해 코드를 작성할 필요가 있습니다.

즉, 디자인 패턴은 기능들을 요리조리 잘 분류하여 재사용성을 높이고 가독성을 높이기 위한 측면에서 

생겨난 이론입니다.

 

** What IS MVC **

MVC 패턴이란 무엇인가!!!

MVC 디자인 패턴은 Model - View - Controller 로 이뤄어져 있습니다.

Model은 데이터의 자료나 데이터를 다루는 함수

View는 사용자에게 보여지는 기능

Controller는 View의 작동을 다루거나 Model의 데이터 처리를 다루는 것 또는 기타 기능

이렇게 기능이 나눠져 있습니다.

이렇게 그림을 보면 바로 알 수 있습니다. 

사용자가 View에서 어떤 기능을 누르면 Controller에서 그 기능을 수행하고 

만약 그 기능이 데이터를 변경하는 거라면 Model에 값을 수정해서 Controller에게 알려줍니다.

그리고 View에게 변경 사항을 사용자에게 알려줍니다.

따라서 Controller는 모든 기능의 중심적인 역할을 한다고 보면 됩니다.

//뷰
class View {
    
    func showInfo(_ info : String){
        print(info)
    }
    
}

//컨트롤러
class Controller {
    
    var view : View?
    var model : Model?
    
    init(_ model : Model , _ view : View){
        self.view = view
        self.model = model
    }
    
    func setModel(_ name : String, _ id : String){
     
        model!.setInfo(name, id)
        
    }
    
    func updateView(){
    
        view!.showInfo(model!.getInfo())
        
    }
    
}

//모델
struct Model{
    
    private var name : String
    private var id : String
    
    init(_ name : String , _ id : String){
        
        self.name = name
        self.id = id
        
    }
    
    mutating func setInfo(_ name : String, _ id : String){
        
        self.name = name
        self.id = id
    }
    
    func getInfo() -> String{
        return "\(name) : \(id)"
    }
    
    
}

let initModel = Model.init("Hururuek", "12345")

let initView = View()

let controller = Controller.init(initModel, initView)

controller.updateView()

controller.setModel("ChapChap", "67890")

controller.updateView()

//결과
Hururuek : 12345
ChapChap : 67890

즉, 위의 코드를 보면 Controller 중심으로 Model과 View가 서로 응답을 취하는 것을 볼 수 있습니다.

위의 코드는 우리가 일반적으로 알고 있는 MVC 패턴이지만,

IOS에서는 MVC 패턴이 조금 다릅니다. (이래서 저도 많이 헷갈렸습니다 ㅠㅠ)

 

** IOS MVC는 기존의 MVC와 다르다? **

결론 부터 말하면 같으나 살짝 다릅니다 ㅎㅎㅎ

애플의 MVC 패턴은 View + Controller - Model 로 구성되어 있습니다. 

그래서 처음 생겨나는 것도 ViewController 입니다. (사실 저는 ViewController를 View 자체로 생각하는 경향이 있습니다.)

class ViewController: UIViewController {

    var myView : View?
    var tistroy : Info?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        tistroy = Info.init("Hururuek", "12")
        
        // Do any additional setup after loading the view.
    }
    
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        print("viewWillLayoutSubviews")
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        print("viewDidLayoutSubView")
        myView = View(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
        myView!.center = view.center
        myView!.changeLabel(tistroy!.makeText())
        view.addSubview(myView!)
    }
    
    @IBAction func changeBTN(_ sender: UIButton) {
        tistroy!.changeInfo("ChapChap", "67")
        myView!.changeLabel(tistroy!.makeText())
    }
    
}

이것이 ViewController 입니다.

우리는 이 ViewController에 StroyBoard로 버튼 View를 하나 만들어 주고

코드로 View를 하나 만들어 줄 것 입니다.

위의 사진을 보면 "Change" 라는 버튼과 빨강색 View가 있습니다.

사실 ViewController에 StroyBoard로 끌어서 뷰를 만들어줘도 되고, 아니면 코드로 View를 만들어 줄 수 있습니다.

override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        print("viewDidLayoutSubView")
        myView = View(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
        myView!.center = view.center
        myView!.changeLabel(tistroy!.makeText())
        view.addSubview(myView!)
    }

우리는 ViewDidLayOut 시점에 빨간색 View를 생성해주는 것을 확인 할 수 있습니다.

사실 StroyBoard로 한다면 위와 같은 작업은 필요가 없습니다.

또한 ViewController에 View를 만들어도 상관 없습니다. 

하지만 가독성을 위해서 View를 따로 만들었고, 기존의 MVC 패턴을 준수한 것 입니다. 

class View: UIView {
    
    var label : UILabel = {
        
        let label = UILabel()
        label.textColor = .white
        label.textAlignment = .center
        return label
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .red
        addSubview(label)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func changeLabel(_ text : String){
        print(text)
        label.text = text
//        setNeedsLayout()
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        print("layoutSubviews")
        label.sizeToFit()
        label.center = CGPoint(x: self.bounds.width / 2, y: self.bounds.height / 2)
        
    }

}

이렇게 뷰 클래스를 생성 해줍니다. 

그리고 모델 클래스 입니다.

struct Info {
    
    var name : String
    var id : String
    
    init(_ name : String, _ id : String){
        self.name = name
        self.id = id
    }
    
    mutating func changeInfo(_ name : String, _ id : String){
        self.name = name
        self.id = id
    }
    
    func makeText() -> String{
        return "\(name) : \(id)"
    }
}

 

그렇다면 코드를 통해 본다면 

View에서는 "changeLabel" 함수와 뷰 생성 등 원초적으로 보여주는 작업에 집중하는 것을 알 수 있고

ViewController에서는 "버튼 뷰 생성" 뿐만 아니라 "changeBTN" 함수 까지 뷰와 기타 기능 까지 모두 관여 하는 것을 알 수 있고

Model에서는 "changeInfo" , "makeText" 는 모델의 값 변경 등 모델과 관련된 기능을 하는 것을 알 수 있습니다.

 

이렇게 해서 View Model Controller 에서 ViewController Model View 까지 다 알아 봤습니다.

애플에서 추구하는 MVC 디자인 패턴은 View + Controller - Model 인 ViewContoller - Model 이지만

장단점이 있습니다.

 

초보자일 경우에 View - Model -Controller을 준수하면서 코드를 작성하기 어렵지만

View와 Controller를 함께 묶는다면 진입장벽을 낮출 수 있습니다.

또한 "viewDidLayoutSubviews" , "viewWillLayoutSubviews" 등 ViewController Life Cycle에 맞도록 개발 할 수 있습니다.

 

하지만 View + Controller는 확실히 ViewController의 코드 길이가 집중되고 가독성이 떨어지게 됩니다.

또한 너무 View - Model이 의존적이게 됩니다.

따라서 큰 프로젝트 일 경우에는 MVC 패턴을 잘 사용하지 않는다고 합니다.

 

소스 코드 : 

github.com/HururuekChapChap/Xcode_TestProj/tree/master/MVC_Test/MVC_Test

 

HururuekChapChap/Xcode_TestProj

My Xcode Test Projects. Contribute to HururuekChapChap/Xcode_TestProj development by creating an account on GitHub.

github.com

참고 사이트 : 

dev-leeyang.tistory.com/21

 

MVC, MVVM, MVP, VIPER, VIP를 알아봅시다.

안녕하세요. 리양입니다 :) 요즘 코로나로 전국적으로 이슈네여 ㅠ ㅠ 다들 몸 조심하시길 바랍니다. 요즘은 패턴에 대해 공부를 하기 시작했어여. 어떻게 layer를 좀 더 잘 나누어서 각 역할을 수

dev-leeyang.tistory.com

 

728x90
반응형

댓글