MVC (Model - View - Controller)
MVC 패턴은 Model과 View, Controller로 코드를 분리하는 디자인 패턴을 말한다. 각각의 요소들은 다음과 같은 역할을 맡는다.
- Model: 화면에 필요한 데이터와 Business Logic을 관리한다.
- View: Model이 가진 데이터를 화면에 보여준다.
- Controller: 모델과 뷰 객체 사이의 브리지 역할을 한다.
The core app objects
Figure 4 represents a fairly typical structure of a UIKit app. You provide the model objects that represent your app’s data structures. UIKit provides most of the view objects, although you can define custom views for your data, as needed. Coordinating the exchange of data between your data objects and the UIKit views are your view controllers and app delegate object.
애플 공식문서에 있는 이미지를 가져왔다. 'Code Structure of a UIKit App' 섹션에 있는 이미지인데, UIKit Apps의 구조를 설명한 그림이다. Model은 앱의 데이터 구조를, View에서는 view object들이나 개발자가 Model의 데이터를 표현하기 위해 직접 만들어서 사용하는 custom view를, Controller는 Model과 View사이에서 인터랙션이나 데이터를 보내주고받는 역할을 하고 있는 걸로 보인다.
Model과 View는 서로 직접 Communication하지 않고 View에서 액션이 일어나게 되면 View는 delegate 패턴 등으로 Controller에 변화를 알린다. Model이 먼저 변하게 된다면(서버로부터 데이터를 받는 경우) 변한 내용을 Controller에 알려서 View를 변화 시킨다고 이해했다.
예제
UserInfoView를 만들어 성과 이름, 나이를 입력할 수 있는 Text Field를 넣고 계산 버튼을 누르면 ResultView 내부의 UILabel에 풀네임과 태어난 연도를 업데이트 해주는 예제를 만들었다.
FirstName과 LastName, Age를 입력받는 텍스트 필드와 Result 버튼이 추가된 UserInfoView를 추가한다. Result 버튼을 누르면 ViewController에 각 텍스트 필드에 입력된 정보를 넘긴다.
import UIKit
protocol UpdateUserInfoDelegate: class {
func updateUserInfo(firstName: String, lastName: String, age: String)
}
class UserInfoView: UIView {
@IBOutlet var firstNameTextField: UITextField?
@IBOutlet var lastNameTextField: UITextField?
@IBOutlet var ageTextField: UITextField?
@IBOutlet var resultButton: UIButton?
weak var delegate: UpdateUserInfoDelegate?
@IBAction func didSelectResultButton(_ sender: Any) {
guard let firstName = self.firstNameTextField?.text,
let lastName = self.lastNameTextField?.text,
let age = self.ageTextField?.text else { return }
self.delegate?.updateUserInfo(firstName: firstName, lastName: lastName, age: age)
}
}
Name과 Year를 표시하는 ResultView를 추가한다. ViewController로부터 데이터를 받아 업데이트 할 수 있도록 updateResultView 메서드를 추가한다.
import UIKit
class ResultView: UIView {
@IBOutlet var nameLabel: UILabel?
@IBOutlet var yearLabel: UILabel?
func updateResultView(name: String, year: String) {
self.nameLabel?.text = name
self.yearLabel?.text = year
}
}
비즈니스 로직을 관리하는 UserInfoModel을 생성한다. (아주 간단하게 짰다.)
ViewController에서는 UserInfoView의 delegate 메서드를 구현하고 ResultView에 데이터를 업데이트할 수 있도록 한다.
import UIKit
class ViewController: UIViewController, UpdateUserInfoDelegate {
@IBOutlet weak var userInfoView: UserInfoView?
@IBOutlet weak var resultView: ResultView?
let userInfoModel = UserInfoModel()
override func viewDidLoad() {
super.viewDidLoad()
self.userInfoView?.delegate = self
}
func updateUserInfo(firstName: String, lastName: String, age: String) {
let fullName = self.userInfoModel.fullName(firstName: firstName, lastName: lastName)
let yearString = self.userInfoModel.yearOfBirth(ageString: age)
self.resultView?.updateResultView(name: fullName, year: yearString)
}
}
결과물은 아래와 같다.
MVC 패턴은 구조가 비교적 간단하기 때문에 처음 입문해서 로직을 분리하며 구현하고 싶을 때 사용하기 좋다. 하지만 앱에 기능이 많이 들어갈수록 뷰 컨트롤러에서 수행되는 코드량이 점점 많아지고(이런 이유로 MVC의 M이 Massive의 약자라는 말도 나온다) 나중에는 뷰컨트롤러의 코드를 읽기가 힘들어진다. 그래서 다음 글에서는 View와 Business Logic, Presentation Logic을 분리한 VIP Pattern에 대해 공부해볼 예정이다.
참고 링크
'iOS' 카테고리의 다른 글
[iOS] UITableView 알아보기 (2) - UITableViewDelegate, UITableViewDataSource (0) | 2021.10.07 |
---|---|
Apple Developer Documentation에서 API Changes 확인하기 (0) | 2021.10.07 |
[iOS] UITableView 알아보기 (1) - UITableView, UITableViewCell이 뭐야? (0) | 2021.10.05 |
[iOS] UIView에 border 추가하기 / 모서리 둥글게 하기 - 코드, 스토리보드 (0) | 2021.09.09 |
[iOS] Clean Swift (VIP Pattern) (0) | 2021.09.07 |