안녕하세요 후르륵짭짭 입니다!
오늘은 디자인 패턴에 대해서 알아보려고 합니다.
제가 디자인 패턴에 대해 처음 알게된 것은 "소프트웨어 공학" 수업을 듣고 나서 입니다.
이때 처음으로 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
참고 사이트 :
'Xcode > Swift - PlayGround' 카테고리의 다른 글
PlayGround) Delegate와 Delegate Data Pass를 알아보자! (0) | 2020.11.04 |
---|---|
PlayGround ) Swift로 RC4 알고리즘에 대해 알아보자! (0) | 2020.10.05 |
PlayGround ) Viewcontroller Life Cycle 이란?? (0) | 2020.09.30 |
PlayGround ) 우선순위 큐를 구현해보도록 하자!!! (0) | 2020.09.19 |
PlayGround) Auto Reference Counting(ARC) 에 대해 알아보자!!! (0) | 2020.08.24 |
댓글