[UIKit] NetflixClone: SearchViewController 1

Junyoung Park·2022년 11월 1일
0

UIKit

목록 보기
72/142
post-thumbnail
post-custom-banner

Building Netflix App in Swift 5 and UIKit (Xcode 13, 2021) - Episode 9 - SearchViewController Part 1

NetflixClone: SearchViewController 1

구현 목표

  • 서치바 UI 및 검색 기능 구현

구현 태스크

  • UISearchController 사용
  • API 검색 및 데이터 패치
  • 커스텀 테이블 뷰 셀 구현 및 데이터 바인딩
  • 검색바 인터렉션 구현

핵심 코드

func getSearchResultContents(with query: String) -> AnyPublisher<[ContentModel], Error> {
        guard let url = URL(string: "\(TMDBConstants.baseURL.rawValue)/3/search/movie?api_key=\(TMDBConstants.API_KEY.rawValue)&language=en-US&query=\(query)&page=1") else { return Fail(error: URLError(.badURL)).eraseToAnyPublisher() }
        return getDataPublisher(with: url)
    }
  • 쿼리 문자열을 통해 API의 데이터를 패치하는 API 함수
import Foundation
import Combine

class SearchViewModel {
    let resultContentsModel: CurrentValueSubject<[ContentModel], Never> = .init([])
    private var cancellables = Set<AnyCancellable>()
    
    init() {
        addSubscription()
    }
    
    private func addSubscription() {
        APICaller
            .shared
            .getUpcomingContents(with: .movie)
            .sink { completion in
                switch completion {
                case .failure(let error): print(error.localizedDescription)
                case .finished: break
                }
            } receiveValue: { [weak self] movieModels in
                self?.resultContentsModel.send(movieModels)
            }
            .store(in: &cancellables)
    }
        
    func getSearchResultContents(with query: String) {
        APICaller
            .shared
            .getSearchResultContents(with: query)
            .sink { completion in
                switch completion {
                case .failure(let error): print(error.localizedDescription)
                case .finished: break
                }
            } receiveValue: { [weak self] resultModels in
                self?.resultContentsModel.send(resultModels)
            }
            .store(in: &cancellables)
    }
}
  • 서치 뷰에서 사용할 뷰 모델 구현
  • 이니셜라이즈 단에서 최신 트렌드 내용의 데이터를 리턴하는 것으로 초기화
  • 쿼리 문자열을 파라미터로 받아 API 함수를 사용
  • resultContentsModel 퍼블리셔를 업데이트함으로써 뷰 컨트롤러에서 UI 패치
private let searchController: UISearchController = {
        let vc = UISearchController()
        vc.searchBar.placeholder = "검색"
        vc.searchBar.searchBarStyle = .minimal
        vc.definesPresentationContext = true
        return vc
    }()
  • 서치 뷰 컨트롤러에서 사용할 검색 바 컨트롤러
private func setUI() {
        view.backgroundColor = .systemBackground
        searchController.searchResultsUpdater = self
        navigationItem.searchController = searchController
        searchController.searchBar.delegate = self
        view.addSubview(tableView)
        tableView.delegate = self
        tableView.dataSource = self
        DispatchQueue.main.async { [weak self] in
            self?.searchController.searchBar.becomeFirstResponder()
        }
    }
  • 컨트롤러 델리게이트 선언 및 뷰 컨트롤러 초기화 시 키보드가 자동으로 세팅되도록 설정
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
        guard
            let query = searchBar.text,
            !query.trimmingCharacters(in: .whitespaces).isEmpty else { return }
        viewModel.getSearchResultContents(with: query)
        searchController.isActive = false
    }
  • 검색 버튼 클릭 시 API 호출을 통한 데이터 패치
  • 받아온 데이터를 통해 테이블 뷰 셀이 자동으로 업데이트
  • 검색 바의 cancel 버튼이 자동으로 클릭, 비활성 상태

구현 화면

profile
JUST DO IT
post-custom-banner

0개의 댓글