Project/MovieClip (54) 썸네일형 리스트형 🔥 MVVM + Combine을 통한 검색기능 구현 1편 패턴 비교 🎯 UISearchController를 활용한 검색 화면 아키텍처 선택: MVVM vs. MVC ✅ MVC 패턴 vs. MVVM 패턴 비교1️⃣ MVC (Model-View-Controller)✅ 장점:비교적 간단하고 빠르게 개발 가능UIKit의 기본 패턴이므로 익숙함❌ 단점:ViewController에 로직이 집중됨 → 거대한 ViewController(= Massive View Controller) 문제가 발생테스트하기 어렵고, 유지보수가 어려워짐💡 적합한 경우:검색 기능이 간단하고, 데이터 처리 로직이 복잡하지 않을 때검색 결과를 바로 네트워크에서 받아와서 UI에 반영하는 경우2️⃣ MVVM (Model-View-ViewModel)✅ 장점:ViewController의 역할을 줄이고, 로직을 Vi.. ✅ MVVM + Combine로 설계한 검색에서 번역 기능 적용하는 최적 방법 🤔 번역 기능은 어디에 구현해야하나?현재 검색 결과의 소개(overview)가 영어로 표시되고 있기 때문에이를 Google Translate API를 사용하여 한국어로 변환하려고 함 🔷 방법1️⃣ SearchViewModel 에서 overview를 번역 후 @Publised 에 저장 2️⃣ SearchResultCell 에서 configure(with: ) 시점에 번역 후 실행🔷 방법 비교방법장점단점SearchViewModel에서 미리 번역✅ ViewModel에서 모든 데이터 관리 ✅ 데이터 변경 시 UI 자동 업데이트❌ 검색 결과가 많으면 API 요청이 많아짐❌ 한 번의 API 요청 지연이 전체 UI 업데이테 영향SearchResultCell에서 번역 실행✅ 필요한 경우에만 번역 요청 ✅ UI .. ❌ 에러 분석 - UICollectionView 2번 dequeue... ✅ 에러 분석 및 해결 방법에러 메시지:Expected dequeued view to be returned to the collection view in preparation for display. When the collection view's data source is asked to provide a view for a given index path, ensure that a single view is dequeued and returned to the collection view. Avoid dequeuing views without a request from the collection view. 🚨 에러 원인:UICollectionView는 cell을 dequeue하면 반드시 반환해야 함현재 .. 🚜 서치 기능 개선 (MVVM + Combine) 📌 수정 전 SearchViewModelclass SearchViewModel: ObservableObject { ... func loadMoreMovies() { guard canLoadMoreMovies else { return } Task { do { moviePage += 1 let moreMovies = try await NetworkManager.shared.searchMovie(with: currentQuery, page: moviePage) DispatchQueue.main.async { le.. 🔍 클로저를 저장하는 변수로? ✅ 클로저를 변수 타입으로? 📌 1. (() -> Void)? 타입 해석var onSearchResultsUpdated: (() -> Void)?(() -> Void)?는 "매개변수가 없고, 반환값도 없는 클로저"를 저장하는 옵셔널 변수를 의미함.해석하면?() → 매개변수가 없음 (입력 X)-> Void → 반환값이 없음 (출력 X)? → 옵셔널 (값이 nil일 수도 있음)📌 onSearchResultsUpdated는 "어떤 동작을 실행할 수 있지만, 필요하지 않을 수도 있는" 함수(클로저)를 저장하는 변수 📌 2. 사용 예시✅ ViewModel에서 클로저 실행class SearchViewModel { var onSearchResultsUpdated: (() -> Void)? // ✅ 클로저.. 📍 함수의 역할 -> createFeaturedSection() { } https://developer.apple.com/documentation/uikit/uicollectionviewcompositionallayout UICollectionViewCompositionalLayout | Apple Developer DocumentationA layout object that lets you combine items in highly adaptive and flexible visual arrangements.developer.apple.com 🔍 createFeaturedSection() { } 이 함수는 TvFeaturedCell을 사용하는 섹션의 UICollectionViewCompositionalLayout을 생성하는 역할을 합니다.즉, 컬렉션 뷰의 특정 섹션을 위한.. 📍함수의 역할 -> reloadData() { } 🔍 reloadData() { } 이 메서드는 컬렉션 뷰의 데이터를 갱신(리로드)하는 역할을 합니다.즉, NSDiffableDataSourceSnapshot을 새로 만들어 데이터를 추가하고, 이를 dataSource에 적용하여 UI를 업데이트하는 함수입니다.private func reloadData() { var snapshot = NSDiffableDataSourceSnapshot() // 섹션 추가 snapshot.appendSections(tvCombineSection.combineTMDB) // 각 섹션의 결과를 TvResultItem으로 래핑하여 추가 for tmdbData in tvCombineSection.combineTMDB { // 각 섹션에 명시.. 📍 함수의 역할 -> createDataSource() { } 🔍 createDataSource() { } 이 메서드는 UICollectionViewDiffableDataSource를 생성하고, 셀과 섹션 헤더를 설정하는 역할 dataSource = UICollectionViewDiffableDataSource섹션 타입: TvTMDBData아이템 타입: TvResultItem→ 각 섹션(TvTMDBData) 안에 여러 개의 아이템(TvResultItem)이 포함된다.셀을 생성 및 구성switch sectionType을 사용하여 각 섹션별로 다른 셀을 반환함.configure(_:with:for:) 메서드를 사용해 적절한 셀을 생성하고 데이터를 적용.섹션 헤더를 설정dataSource?.supplementaryViewProvider를 사용해 섹션별 헤더 뷰를 구성함.. 이전 1 2 3 4 5 6 7 다음