도서 검색 앱을 MVVM 패턴으로 리팩토링한 과정을 정리하였다. 기존의 MVC 패턴으로 구현된 코드를 MVVM으로 전환하면서 코드의 구조를 개선하고 유지보수성을 높이는 데 중점을 두었다.
기존의 단일 파일 구조에서 다음과 같이 역할별로 파일을 분리하였다:
BookDataApp/
├── Models.swift // 데이터 모델
├── ViewModels.swift // 비즈니스 로직
└── Views.swift // UI 요소
카카오 도서 검색 API를 연동하여 실제 도서 데이터를 가져오도록 구현하였다:
struct BookSearchResponse: Codable {
let documents: [Book]
let meta: Meta
}
struct Book: Codable {
let authors: [String]
let contents: String
let datetime: String
let isbn: String
let price: Int
let publisher: String
let sale_price: Int
let status: String
let thumbnail: String
let title: String
let translators: [String]
let url: String
}
각 화면별로 ViewModel을 구현하여 비즈니스 로직을 분리하였다:
class BookSearchViewModel {
private let apiKey = "YOUR_API_KEY"
private(set) var books: [Book] = []
var onBooksUpdated: (() -> Void)?
func searchBooks(query: String) {
// API 호출 및 데이터 처리
}
}
class BookDetailViewModel {
let book: Book
var title: String {
return book.title
}
var priceText: String {
return "\(book.price)원"
}
func loadImage(completion: @escaping (UIImage?) -> Void) {
// 이미지 로딩 로직
}
}
class BookSearchViewController: UIViewController {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "BookSearchCell", for: indexPath) as! BookSearchCell
cell.configure(title: "세이노의 가르침", price: "14,000원")
return cell
}
}
class BookSearchViewController: UIViewController {
private let viewModel = BookSearchViewModel()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "BookSearchCell", for: indexPath) as! BookSearchCell
let book = viewModel.books[indexPath.row]
cell.configure(title: book.title, price: "\(book.price)원")
return cell
}
}
MVVM 패턴을 적용하면서 다음과 같은 개선을 이루었다: