[TIL / 25.04.16] Lv3 서치바 관련 트러블슈팅 기록

2025. 4. 16. 17:35·iOS/Swift

기존엔 navigationBar.searchController = searchController하는 식으로 직접 넣어서 했는데

검색 시 아무리 설정해줘도 상단 라지타이틀이 보여야하는데 올라가는 점이 맘에 들지 않았다. 

 

그럼.. navigationBar 내부 설정에 searchController와 관련된 일정한 동작이 이미 구현되어있다면..!?

SearchController를 navigationBar 밖으로 빼서 고정하게 된다면 largeTitle에 문제가 없지 않을까!

import UIKit

class MainViewController: UIViewController {
    private let mainView = MainView()
    private let viewModel = MainViewModel()
    private let searchController = UISearchController()

    override func viewDidLoad() {
        super.viewDidLoad()

        configure()
        Task {
            await fetchData()
        }

    }

    private func fetchData() async {
        do {
            try await viewModel.fetchData()
            await MainActor.run {
                mainView.reloadTableView()
            }
        } catch let error as APIError {
            showAlert(message: error.errorMessage)
        } catch {
            showAlert(message: "데이터 로드에 실패했습니다.")
        }
    }

    private func searchControllerSetting() {
        searchController.searchResultsUpdater = self
        searchController.searchBar.placeholder = "통화 검색"
        searchController.searchBar.searchBarStyle = .minimal
        searchController.searchBar.showsCancelButton = false
    }

    private func navigationControllerSetting() {
        navigationController?.navigationBar.prefersLargeTitles = true
        navigationController?.navigationBar.topItem?.title = "환율 정보"
    }
}

private extension MainViewController {
    func configure() {
        mainView.configure(dataSource: self, delegate: self)
        searchControllerSetting()
        navigationControllerSetting()
        setHierarchy()
        setConstraints()
    }

    func setHierarchy() {
        view.addSubViews(views: searchController.searchBar, mainView)
    }

    func setConstraints() {
        searchController.searchBar.snp.makeConstraints { make in
            make.top.directionalHorizontalEdges.equalTo(view.safeAreaLayoutGuide)
        }

        mainView.snp.makeConstraints { make in
            make.top.equalTo(searchController.searchBar.snp.bottom)
            make.directionalHorizontalEdges.bottom.equalTo(view.safeAreaLayoutGuide)
        }
    }
}

extension MainViewController: UITableViewDataSource, UITableViewDelegate {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return viewModel.filteredItems.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: ExchangeRateCell.identifier) as? ExchangeRateCell else {
            return UITableViewCell()
        }

        let currencyItem = viewModel.filteredItems[indexPath.row]
        cell.configure(with: currencyItem)

        return cell
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 60
    }
}

extension MainViewController: UISearchResultsUpdating {
    func updateSearchResults(for searchController: UISearchController) {
        guard let searchText = searchController.searchBar.text else { return }

        if !searchText.isEmpty {
            viewModel.filterCurrencyItems(by: searchText)
            mainView.reloadTableView()
        } else {
            viewModel.resetFilteredItems()
            mainView.reloadTableView()
        }
    }
}

 

결과는 

이거보고 그저 웃겨서 말도 안나옴

저 텍스트필드를 탭하면 상단으로 올라가려는게 더 극단적으로 변했다...

 

그래서 그냥 searchController의 편의성을 포기하고 searchBar 자체를 View 자체에 따로 고정해서 관리하기로 했다.

 

import UIKit
import SnapKit

class MainView: UIView {
    private let searchBar: UISearchBar = {
        let searchBar = UISearchBar()
        searchBar.placeholder = "통화 검색"
        searchBar.backgroundImage = UIImage()
        searchBar.searchBarStyle = .default
        searchBar.showsCancelButton = false

        return searchBar
    }()

    private let tableView: UITableView = {
        let tableView = UITableView()
        tableView.backgroundColor = .systemBackground
        tableView.register(ExchangeRateCell.self, forCellReuseIdentifier: ExchangeRateCell.identifier)
        tableView.allowsMultipleSelection = false

        return tableView
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)

        configure()
    }

    @available(*, unavailable, message: "storyboard is not supported.")
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented.")
    }

    func configureTableView(dataSource: UITableViewDataSource, delegate: UITableViewDelegate) {
        tableView.dataSource = dataSource
        tableView.delegate = delegate
    }

    func configureSearchBar(delegate: UISearchBarDelegate) {
        searchBar.delegate = delegate
    }

    func reloadTableView() {
        tableView.reloadData()
    }

    func scrollToTop() {
        let indexPath = IndexPath(row: 0, section: 0)
        self.tableView.scrollToRow(at: indexPath, at: .top, animated: false)
    }

}

private extension MainView {
    func configure() {
        setLayout()
        setHierarchy()
        setConstraints()
    }

    func setLayout() {
        backgroundColor = .systemBackground
    }

    func setHierarchy() {
        addSubViews(views: searchBar, tableView)
    }

    func setConstraints() {
        searchBar.snp.makeConstraints { make in
            make.top.directionalHorizontalEdges.equalTo(safeAreaLayoutGuide)
        }

        tableView.snp.makeConstraints { make in
            make.top.equalTo(searchBar.snp.bottom)
            make.directionalHorizontalEdges.bottom.equalTo(safeAreaLayoutGuide)
        }
    }
}
extension MainViewController: UISearchBarDelegate {
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        if !searchText.isEmpty {
            viewModel.filterCurrencyItems(by: searchText)
            mainView.reloadTableView()
        } else {
            viewModel.resetFilteredItems()
            mainView.reloadTableView()
        }
    }

    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
        searchBar.resignFirstResponder()
    }
}

 

SearchController의 경우 검색어에 반응해 업데이트하는 로직에 편의성이 이미 제공되고 있었지만 searchBar의 경우 직접 구현해줘야했다. 다만 이미 textField의 메서드를 쓸 수 있어 textDidChange에 트리거를 걸어 해당 로직을 수행하도록 했다. 

 

 

요런식으로 UISearchBar만 레이아웃 고정 후 delegate 관련 설정들을 해주어 고정하도록 했다.

UISearchController의 경우 복잡한 검색에 유용한 기능들이 많아서 쓰기 좋다고는 하나 이런 요구사항을 충족해야할 경우 UISearchBar로 만들어 모든 요구사항을 별도로 구현해줘야하는 불편함이 있을 것 같은데 아직 모르는 부분이 있을지도 모를지도...!

 

기본 제공되는 기능과 요구사항이 상이한 부분이 있다면 꽤 골치 아파질 것 같다.

'iOS > Swift' 카테고리의 다른 글

[WIL / 25.05.06] 8~9주차 회고 및 To-do  (2) 2025.05.06
[TIL / 25.04.17] URLSession으로.. 네트워크 통신을 어떻게 하는지.. 보여줄래요  (2) 2025.04.17
[TIL / 25.04.11] UICollectionView Compositional Layout 1  (0) 2025.04.11
[TIL / 25.03.31] 앨범에서 사진 고르고 잘라서 쓸 수 있도록! (feat. PHPickerViewController, TOCropViewController)  (0) 2025.03.31
[TIL / 25.03.28] 과제 5, 스택뷰가 보이지 않는 문제 해결  (2) 2025.03.28
'iOS/Swift' 카테고리의 다른 글
  • [WIL / 25.05.06] 8~9주차 회고 및 To-do
  • [TIL / 25.04.17] URLSession으로.. 네트워크 통신을 어떻게 하는지.. 보여줄래요
  • [TIL / 25.04.11] UICollectionView Compositional Layout 1
  • [TIL / 25.03.31] 앨범에서 사진 고르고 잘라서 쓸 수 있도록! (feat. PHPickerViewController, TOCropViewController)
subkyu-ios
subkyu-ios
subkyu-ios 님의 블로그 입니다.
  • subkyu-ios
    subkyu-ios 님의 블로그
    subkyu-ios
  • 전체
    오늘
    어제
    • 분류 전체보기 (48) N
      • iOS (32) N
        • Swift (32) N
      • 내일배움캠프 (7)
      • Git, Github (3)
      • Algorithm (6)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    협업
    사전캠프
    알고리즘
    본캠프
    algorithm
    github
    회고
    KPT
    TableView
    트러블슈팅
    내일배움캠프
    Wil
    UIKit
    최적화
    Swift
    stackview
    tabman
    ios
    til
    프로그래머스
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
subkyu-ios
[TIL / 25.04.16] Lv3 서치바 관련 트러블슈팅 기록
상단으로

티스토리툴바