Xcode/Swift - PlayGround

PlayGround ) Design Pattern (MVC)

후르륵짭짭 2020. 10. 2. 23:24
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
반응형