FiveMovies Project (3)

ulls12·2024년 1월 19일
0

Swift TIL

목록 보기
34/60

SearchView 구성하기

기본적으로 검색 기능을 구현하기 위해서는 UISearchBar라는 View Componant를 사용해야 한다. 그리고 검색 결과를 나타내기 위해서UICollectionView를 사용하고 검색창에 입력한 결과를 콜렉션뷰에 반영시켜줘야 한다. 나머지 틀은 MovieListView 구성방식이랑 똑같기 때문에 수월하게 진행되었다. 가장 어려운 부분은 뷰간의 데이터 연동이 될 것 같다.

1. UISearchBar

앱을 개발할 때 가장 다루기 어려운 건, 오늘 처음 써보는 게 아닐까 싶다. 사실 콜렉션뷰도 전 프로젝트에서 다뤘었고 많이 데여봤기 때문에 이젠 익숙해졌다. 새로운 뷰를 익힐때마다 어색하고 접근하기 힘들다. 우선 검색창으로 구현해야할 기능들이 무엇이 있는지 생각해보았다.
검색해서 나온 데이터를 담을 변수를 설정해준다. 타이핑을 하면 그 타이핑한 문자열을 키워드에 넣어 데이터를 호출하는 것이다. 그럼 첫째, 타이핑 관련 메서드와 둘째, 문자열을 URL 속에 넣어 데이터를 호출하는 메서드 두개가 필요하다.

//VC에서 구현된 코드

    //타이핑 시, 문자열을 getSearchedMovies로 키워드를 받는 메서드
    lazy var filteredMovies: [MovieData.Movie] = []
    
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        MovieData.shared.getSearchedMovies(userInput: searchText, completion: { [weak self] in
            self?.filteredMovies = MovieData.shared.searchedMovies
            DispatchQueue.main.async {
                self?.searchCollectionView.reloadData()
            }
        })
    }
    //엔터를 누르면 키보드가 내려가는 메서드
    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
        searchBar.resignFirstResponder()
    }

//Data.swift 에서 구현된 모델
    public func getSearchedMovies(userInput:String, completion: @escaping () -> Void) {
        
        //파일 형식과 API키를 정의한 헤더부
        let headers = [
            "accept": "application/json",
            "Authorization": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJmM2Q1ZTNlYWY2MGViNWY3Njg5YjhjMjIxNTYyMzlhNCIsInN1YiI6IjY1YTUwZDgwMWZiOTRmMDBjMDc0YTFhNyIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.4pi9VmylhkY94DoJk6s4Ol7txHjXcyonKy3PeI9ZdS8"
        ]
        
        //요청을 보낼 URL
        let url = URL(string: "https://api.themoviedb.org/3/search/movie?query=\(userInput)&include_adult=false&language=ko-KR&page=1")!
        
        //URL에 요청
        var request = URLRequest(url: url, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0)
        
        //HTTP 메서드 설정
        request.httpMethod = "GET"
        
        //요청에 헤더부 추가
        request.allHTTPHeaderFields = headers
        
        let session = URLSession.shared
        let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) in
            
            //에러 처리
            if let error = error {
                print("Error fetching data: \(error)")
                return
            }
            
            //데이터 옵셔널 바인딩
            guard let data = data else {
                print("No data received")
                return
            }
            
            //데이터 처리
            do {
                let decoder = JSONDecoder()
                let result = try decoder.decode(Result.self, from: data)
                self.searchedMovies = result.results
                completion()
                print ("검색 영화 세팅 완료")
            } catch {
                print("Error parsing JSON: \(error)")
            }
            
        })
        dataTask.resume()
    }

(userInput)이 검색바에서 타이핑을 치면 나오는 값이 나타내는 부분이고 API에서 검색기능을 직접 제공하기 때문에 각각의 문자열을 비교해서 데이터를 가져오는 메서드는 구현할 필요가 없었다.
그 이후로 검색바 외곽선을 지우는 작업 & placeholder 설정 & delegate 설정을 해주면 검색바 작업은 끝이난다.

    override func viewDidLoad() {
        super.viewDidLoad()

        searchBar.searchBarStyle = .minimal
        searchBar.placeholder = "Enter Movie Title"
        searchBar.delegate = self
    }

2. CollectionView 설정하기

변수랑 동일한 데이터만 이미지로 표현해주기 위해 cellForItemAt에 fiteredMovies가 순서대로 진행될수 있도록 indexPath.row로 설정해준다

  func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        print(filteredMovies.count)
        return filteredMovies.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let searchCell = collectionView.dequeueReusableCell(withReuseIdentifier: "searchCell", for: indexPath) as! SearchCell
        searchCell.setCell(filteredMovies[indexPath.row])

        
        return searchCell
    }

cell에 넣을 이미지를 poster_Path로 이어줘야하기 때문에 String값이 URL에 들어가도록 설정해주고 각 셀의 크기들을 MovieListView에서 설정했던 것처럼 세팅해준다.

3. Data Flow 생각하기

cell을 눌렀을 때 화면전환이 일어나고 MovieDetailView로 넘어가게 된다. 단순히 화면전환만 진행되는 것이 아닌 Data도 같이 들고 가야한다. 여러가지 방법으로 데이터를 전달할 수 있지만, indexPath를 이용하여 간단하게 데이터를 전달해주기로 했다.

  func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        //선택된 cell에 해당되는 데이터 가져오기
        let selectedMovie = filteredMovies[indexPath.row]
        
        let MovieDetailStoryboard = UIStoryboard(name: "MovieDetailStoryboard", bundle: nil)
        
        guard let MovieDetailViewController = MovieDetailStoryboard.instantiateViewController(identifier: "MovieDetail") as? MovieDetailViewController else {
             return
        }
        //MovieDetailViewController의 movieData 프로퍼티에 인스턴스
        MovieDetailViewController.movieData = selectedMovie
        
        MovieDetailViewController.modalPresentationStyle = .automatic
        
        self.present(MovieDetailViewController, animated: true)

MovieDetailViewController에 인스턴스로 담을 프로퍼티를 만들어주고 그 할당받을 코드를 didSelectItemAt에 설정해주면 데이터가 전달된다. 생각보다 엄청 간단하게 구현할 수 있었다.

내일 할 일

  1. cell 이미지 호출하는 함수 하나로 간소화하기
  2. 전체적인 Layout 다듬기
  3. 다른 팀원들의 UI 다듬기
profile
I am 개발해요

0개의 댓글