Project/CafePoCa

🔍 SearchController를 통해 검색 기능 구현하기

밤새는 탐험가89 2025. 6. 10. 18:31

360

 

🔍 구현하려는 상황

  • homeHeaderView에 위치한 searchTextField로부터 입력받은 텍스트를 통해 검색

 

✅ searchTextField에서 입력받은 텍스트를 KeywordSearchViewController에 델리게이트 패턴으로 전달 

class HomeHeaderView: UIView {
    
    // MARK: - Variable
    weak var delegate: HomeHeaderViewDelegate?
    ...
}

extension HomeHeaderView {
    
    private func setupGesture() {
        ...
        searchButton.addTarget(self, action: #selector(didTappedSEarchButton), for: .touchUpInside)
    }
    ... 
    @objc private func didTappedSEarchButton() {
        let keyword = searchTextField.text ?? ""
        delegate?.didTappedSearchButton(with: keyword)
    }
}


protocol HomeHeaderViewDelegate: AnyObject {
    ...
    func didTappedSearchButton(with keyword: String)
}

 

✅ HomeViewController에서 델리게이트 패턴에 따른 함수 구체화

extension HomeViewController: HomeHeaderViewDelegate {
    ...
    
    func didTappedSearchButton(with keyword: String) {
        print("✅ 현재 눌린 검색어: \(keyword)")
        UIView.animate(withDuration: 0.25) {
            self.view.endEditing(true)
        }
        let vc = KeywordSearchViewController(with: keyword)
        navigationController?.pushViewController(vc, animated: true)
    }
}

 

✅ UISearchController를 담고 있는 KeywordSearchViewController 설계

import UIKit

class KeywordSearchViewController: UIViewController {
    
    // MARK: - Variable
    private var keyword: String = ""
    private var shouldActivateSearch: Bool = true
    
    
    // MARK: - UI Component
    private lazy var searchController: UISearchController = {
        let controller = UISearchController(searchResultsController: resultsViewController)
        controller.searchResultsUpdater = self
        controller.obscuresBackgroundDuringPresentation = false
        controller.searchBar.placeholder = "Search"
        return controller
    }()
    
    private let resultsViewController = KeywordResultsViewController()
    
    
    // MARK: - Init
    init(with keyword: String) {
        super.init(nibName: nil, bundle: nil)
        self.keyword = keyword
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
    // MARK: - Life Cycle
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBackground
        searchControllerSetup()
        setupNavigationBar()
        
        searchController.searchBar.text = keyword
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        if shouldActivateSearch {
            shouldActivateSearch = false // 한 번만 실행되도록 방지
            searchController.isActive = true
            
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
                self.searchController.searchBar.becomeFirstResponder()
                self.resultsViewController.updateResults(for: self.keyword)
            }
        }
    }
    
    
    // MARK: - Function
    private func searchControllerSetup() {
        navigationItem.searchController = searchController
        definesPresentationContext = true
    }
}


// MARK: - Extension: UISearchResultsUpdating
extension KeywordSearchViewController: UISearchResultsUpdating {
    func updateSearchResults(for searchController: UISearchController) {
        guard let query = searchController.searchBar.text,
              !query.isEmpty,
              let resultsVC = searchController.searchResultsController as? KeywordResultsViewController else {
            return
        }
        resultsVC.updateResults(for: query)
    }
}


// MARK: - Extension: NavigaitonBar Setup
extension KeywordSearchViewController {
    
    private func setupNavigationBar() {
        navigationItem.backBarButtonItem?.isHidden = true
        
        let config = UIImage.SymbolConfiguration(pointSize: 20)
        let backButtonImage = UIImage(systemName: "arrow.backward.square", withConfiguration: config)
        let backButton = UIBarButtonItem(image: backButtonImage, style: .plain, target: self, action: #selector(backButtonTapped))
        backButton.tintColor = .label
        self.navigationItem.leftBarButtonItem = backButton
        navigationItem.title = "Search"
        
    }
    
    @objc private func backButtonTapped() {
        navigationController?.popViewController(animated: true)
    }
}

 

🔥 검색창에 검색어를 입력하고 난 후에 검색버튼을 누르면 바로 검색 결과가 보이게 하기 위해서 아래 코드 추가 

아래 코드 없이는, 검색버튼을 누르면 검색결과가 바로 보이지 않음 

override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = .systemBackground
    searchControllerSetup()
    setupNavigationBar()

    searchController.searchBar.text = keyword
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    if shouldActivateSearch {
        shouldActivateSearch = false // 한 번만 실행되도록 방지
        searchController.isActive = true

        DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
            self.searchController.searchBar.becomeFirstResponder()
            self.resultsViewController.updateResults(for: self.keyword)
        }
    }
}

 

✅ 검색결과를 보여줄 KeywordResultsViewController 구현 

  • 간단한 더미데이터를 통해 기능 확인
  • 검색결과는 간단히 테이블뷰로 보여줌
class KeywordResultsViewController: UIViewController {
    
    
    // MARK: - Variable
    private var dummyData: [String] = ["스타벅스", "메가커피", "컴포즈커피", "카페베네", "할리스커피"]
    private var results: [String] = []
    
    
    // MARK: - UI Component
    private var tableView: UITableView = UITableView()
    
    
    // MARK: - Life Cycle
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBackground
        tableViewSetup()
    }
    
    
    // MARK: - Function
    private func tableViewSetup() {
        view.addSubview(tableView)
        tableView.frame = view.bounds
        tableView.showsVerticalScrollIndicator = false
        tableView.dataSource = self
    }
    
    func updateResults(for query: String) {
        print("🔍 검색어: \(query)")
        results = dummyData.filter { $0.localizedCaseInsensitiveContains(query)}
        tableView.reloadData()
    }
}


// MARK: - Extension: UITableViewDataSource
extension KeywordResultsViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return results.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell()
        cell.textLabel?.text = results[indexPath.row]
        return cell
    }
}