MVC 패턴 적용하여 테이블 뷰 구성하기

 

MVC 패턴 적용하여 테이블 뷰 구성하기

지난번 MVC 패턴의 기본 개념정도만 정리하는데 그친 반면에 오늘은 이 패턴을 직접 적용시켜 간단한 테이블 뷰를 만들어 보려고 한다.

 

Swift Architecture , MVC 개념 정리

아키텍처(Architectuer) 애플리케이션을 설계하고 구축하는데 사용되는 구조와 패턴을 나타낸다. 모델의 구성과 동작 원리, 구성요소 간의 관계 및 시스템 외부 환경과 관계 등 포괄하여 설명하는

dongdida.tistory.com

먼저 MVC 패턴을 다시 한번 간단하게 말해보면 소스 코드 설계 기법으로써, 모델(Model) , 뷰(View), 컨트롤러(Controller) 의 핵심구조를 이용하여 애플리케이션을 설계하는 것을 말한다.

모델(Model)은 데이터를 담당하고 뷰(View)는 데이터에 대한 화면 표현을 담당하며, 컨트롤러(Controller)는 모델과 뷰 사이에 위치하여 데이터를 가공, 뷰로 전달하는 역할을 한다.

이런 MVC 패턴을 사용하는 이유는 데이터와 비즈니스 로직을 시각적인 표현으로 분리함으로써 보다 편리하게 구성하고 유지보수를 용이하게 하는데 목적이 있다.


이제 실제로 간단하게 구현을 해보면서 이해를 해보자!

Model

사진과 같이 M - V - C 를 각각의 역할에 맞춰 별도의 파일을 생성하여 구분한다.

먼저 영화를 소개하는 테이블 뷰의 경우, 모델 내 셀에서 표시해줄 예정인 정보들을 class 혹은 struct 를 사용하여 정렬한다.

import UIKit   // 이때 UIKit 이 제대로 인포트되어있는지 확인

struct Movie {
    var movieImage: UIImage?
    let movieName: String?
    let movieDescription: String?
}

그리고 이 비즈니스 모델의 데이터 집합을 직관적으로 확인할 수 있는 데이터 매니저를 생성하여 테이블 뷰 셀 내 확인될 데이터 정보들을 모아 한눈에 볼 수 있도록 배치한다.

import UIKit

class DataManager {
    var movieDataArray: [Movie] = []
    
    func makeMovieData() {
        movieDataArray = [
            Movie(movieImage: UIImage(named: "batman.png"), movieName: "배트맨", movieDescription: "배트맨이 출현하는 영화"),
            
        ]
    }
    
    func getMovieData() -> [Movie] {
        return movieDataArray
    }
}

View

그 다음 View 에는 말 그대로 사용자가 보고 있는 인터페이스 즉 사용자가 보고 상호 작용을 할 수 있는 요소들을 넣어준다.

이 작업물 내 사용자가 보고 상호 작용하는 것은 스토리보드와 그 안의 컴포넌트들 이기 때문에 따로 구분지어 View 에 넣어준다.

컴포넌트들은 곧 데이터가 들어가 셀로 표현될 예정이기 때문에 데이터를 담을 변수를 설정하여 IBOutlet 으로 연결해준다.

Controller

 

다음 Controller는 사용자와 모델 간의 통신을 조정하고 사용자 인터페이스의 비즈니스 로직을 구현하는 역할을 담당하기 때문에 데이터를 전달하기 위한 역할을 하는 로직들을 담아준다.

테이블뷰를 활용하여 그 안에 셀을 통해 정보를 전달할 목적을 가지고 있으므로,

UITableViewDataSource 불러 오는 역할도 여기서 담당한다.

extension ViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        //print(#function)
        return movieArray.count
    } // 표시할 셀 갯수
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        //print(#function)
        let cell = tableView.dequeueReusableCell(withIdentifier: "MovieCell", for: indexPath) as! MovieCell
        
        let array = movieDataManager.getMovieData()
        
        let movie = array[indexPath.row]
        
        cell.mainImageView.image = movie.movieImage
        cell.movieNameLable.text = movie.movieName
        cell.descriptionLable.text = movie.movieDescription
        cell.selectionStyle = .none

        return cell
    }
}

UITableViewDataSource 를 불러왔기 때문에 그 안에 두가지 필수 요소를 성립시켜줘야 하는데 하나는 표시할 셀의 갯수를 나타내는 함수이고 다른 함수는 셀을 재사용하므로써 넣어야하는 필수 조건 및 데이터를 담는 함수를 선언한다.

이 중 가장 이해가 어려웠던 부분에 대해서 잠시만 짚고 넘어가자면

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        //print(#function)
        let cell = tableView.dequeueReusableCell(withIdentifier: "MovieCell", for: indexPath) as! MovieCell

바로 이부분이다. cell 이라는 변수에 MovieCell 의 값을 넣고 싶은 경우이다.

이 때 타입 캐스팅을 해주어야 하는데 그 이유는 타입 캐스팅을 하기 전의 cell 타입을 확인하면 테이블뷰셀로 나와있는 것을 볼 수 있다. 현재 가져와야할 데이터의 타입이 아닌 것이다.

정상적으로 데이터를 가져오고 싶다면, 데이터를 저장해둔 MovieCell 에서 데이터를 가져와야 하기 때문에 타입캐스팅을 하여 cell 의 타입을 MovieCell 로 맞춰 줘야 그 안에있는 데이터를 가져와 정상적으로 테이블 뷰 셀 내 넣어줄 수 있다.

테이블 뷰는 정말 데이터를 어떻게 저장하고 그 데이터를 어떻게 가져와 사용하는지가 정말 중요한 것 같다.

이 방식이 자유로워지기 위해 데이터를 전달하고 저장하는 방법을 반복 숙달해야될 것 같다. 😊