[ProJect 일지] 영화 예매 앱 만들기 (5)

2024.04.22 - [◽️ Programming/T I L] - [ProJect 일지] 영화 예매 앱 만들기 (1)

2024.04.23 - [◽️ Programming/T I L] - [ProJect 일지] 영화 예매 앱 만들기 (2)

2024.04.24 - [◽️ Programming/T I L] - [ProJect 일지] 영화 예매 앱 만들기 (3)

2024.04.25 - [◽️ Programming/T I L] - [ProJect 일지] 영화 예매 앱 만들기 (4)

 

오늘은 전체적인 디테일을 다듬고 나머지 기능구현을 모두 완료하였다.

하나하나 오늘 구현한 내용을 살펴보자

 

자동 로그인 기능

로그인 할때 사진에 보이는 자동 로그인 버튼을 누른 상태로 로그인을 하게 되면 로그아웃을 해 로그인 페이지로 넘어와도 이메일과 패스워드가 남아있어 쉽게 로그인이 가능하도록 설정해놨다.

var isAutoLoginEnabled: Bool = false

@IBAction func saveLoginDataTapped(_ sender: UIButton) {
    sender.isSelected.toggle()
    print(sender.isSelected)
    UserDefaults.standard.set(sender.isSelected, forKey: "isAutoLoginEnabled")
    
    if sender.isSelected {
        saveLoginInfo()
    }
}

먼저 버튼을 누르면 버튼의 Bool 값을 따로 UserDefaults에 저장해 로그인에 성공하면 로그인 정보와 함께 저장되도록 구현한다.

 

그 다음 이 내용을 바탕으로 해당 컨트롤러의 시점을 활용해 로그인 페이지로 넘어왔을때 버튼의 Bool 값을 확인하여 각각의 텍스트 필드에 값을 넣어줄지 확인한다.

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    
    if let appDelegate = UIApplication.shared.delegate as? AppDelegate,
       let loggedInUserInfo = appDelegate.loggedInUserInfo,
       let email = loggedInUserInfo.keys.first,
       let password = loggedInUserInfo.values.first,
       let isAutoLoginEnabled = UserDefaults.standard.object(forKey: "isAutoLoginEnabled") as? Bool {
        
        if isAutoLoginEnabled {
            loginIdTextField.text = email
            loginPasswordTextField.text = password
            autoLoginButton.isSelected = true
        } else {
            // 자동 로그인이 비활성화되어 있으면 아무 동작도 하지 않음
        }
    }
}

이렇게 구현하면 자동로그인을 체크하고 로그인 한 후 로그아웃을 눌러 로그인으로 돌아가면 텍스트필드의 값이 저장되어 바로 로그인이 가능하며, 체크를 하지 않고 로그인 하면 텍스트필드가 비어있다.

 

 

로그아웃 구현

마이페이지 내 로그아웃 버튼을 활용해 누르면 로그인 페이지로 다시 넘어갈 수 있도록 구현해보자

 

테이블 뷰 셀안에 있는 버튼을 눌러 화면전환을 하기 위해서는 일반적인 VC에서 하는 방법과는 살짝 다르다. 먼저 셀에서는 present 구현이 불가하니 VC로 해당 메서드를 이동해 구현하는 과정이 필요하다.

 

이 방법은 크게 두가지가 있는데 먼저 프로토콜을 구성해 화면을 전환하는 방법과 내가 사용한 클로저를 활용한 방식이있다.

var logOutButtonAction: (() -> Void)?

@IBAction func logOutButtonTapped(_ sender: UIButton) {
    logOutButtonAction?()
}

이렇게 테이블 뷰 셀에서 클로저를 활용해 메서드를 구현한 뒤 해당 메서드는 VC에서 구현한다.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
	guard let cell = tableView.dequeueReusableCell(withIdentifier: "ProfileCell", for: indexPath) as? ProfileCell else { return UITableViewCell() }
	
				cell.logOutButtonAction = { [weak self] in
        print("로그아웃 버튼이 눌렸습니다.")
        let storyboard = UIStoryboard(name: "Login", bundle: nil)
        guard let loginVC = storyboard.instantiateViewController(withIdentifier: "LoginVC") as? LoginViewController else { return }
        
        loginVC.modalPresentationStyle = .fullScreen
        self?.present(loginVC, animated: true, completion: nil)
    }
}

테이블 뷰 데이터 소스를 통해 테이블 뷰 셀을 타입 캐스팅 했기 때문에 위에 있는 IBAction 에 접근할 수 있다.

 

이렇게 접근해 화면 전환되는 메서드를 구현해두면 셀에서 로그아웃 버튼을 누르면 로그인 화면으로 이동하게 된다.

 

영화 검색 페이지 서치바 구현

영화 검색 페이지 내 서치바를 넣어 찾고싶은 영화를 검색하면 필터링이 되어 보여지도록 구성했다.

func fetchMovieData() {
    netWorkingManager.fetchCombinedMovies { [weak self] result in
        switch result {
        case .success(let combinedData):
            let popularData = combinedData.popular
            let topRatedData = combinedData.topRated
            let upcomingData = combinedData.upcoming
            
            do {
                let decoder = JSONDecoder()
                
                let popularWelcome = try decoder.decode(Welcome.self, from: popularData)
                let topRatedWelcome = try decoder.decode(Welcome.self, from: topRatedData)
                let upcomingWelcome = try decoder.decode(Welcome.self, from: upcomingData)
                
                var allMovies: [Movie] = []
                allMovies.append(contentsOf: popularWelcome.results)
                allMovies.append(contentsOf: topRatedWelcome.results)
                allMovies.append(contentsOf: upcomingWelcome.results)
                
                let combinedWelcome = Welcome(results: allMovies)
                
                self?.totalMovie = combinedWelcome
                self?.searchResults = allMovies
                
                DispatchQueue.main.async {
                    self?.collectionView.reloadData()
                }
            } catch {
                print("Error decoding movies: \\(error)")
            }
            
        case .failure(let error):
            print("Error fetching combined movies: \\(error)")
        }
    }
}

먼저 목록 페이지에 있는 모든 영화를 모아 데이터를 한곳에 모을 수 있도록 메서드를 구현했다.

extension MovieSecrchViewController: UISearchBarDelegate {
    
    func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
        searchBar.text = ""
        searchResults = totalMovie?.results ?? []
        collectionView.reloadData()
    }

서치바 델리게이트를 선언한 뒤 서치바를 선택했을때 그 값이 비어있다면 모든 영화가 보여지도록 코드를 구현한 뒤 컬렉션 뷰를 리로드 하여 정보를 업데이트 한다.

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    if totalMovie == nil {
    } else {
        print("totalMovie is not nil")
    }
    
    if let totalMovie = totalMovie {
        if searchText.isEmpty {
            searchResults = totalMovie.results
        } else {
            searchResults = totalMovie.results.filter { $0.title.lowercased().contains(searchText.lowercased()) }
        }
        collectionView.reloadData()
    }
}

그리고 서치바의 텍스트 값이 변할때 마다 동일한 내용으로 값을 필터링 하는 고차함수를 넣어 원하는 제목값만 필터링해 해당하는 영화만 컬렉션 뷰에 보여지도록 리로드하여 값을 업데이트한다.

이렇게 구현하면 사진과 같이 원하는 값만 나오게 된다.

 

이렇게 구현을 마무리한 뒤 지금까지 구현한 코드 및 디자인을 조금 더 다듬는 과정을 거쳤다.

 

이렇게 두번째 팀프로젝트가 거의 마무리 되었다. 주말에 조금 더 다듬고 발표하면 끝~