
구현할 SearchView는 한글자 한글자 입력시마다
해당 키워드와 같은 키워드인 문자들을 호출한다.
현재 스터디로 UI개발을 코드베이스로 하고있어
스토리보드는 클래스와의 연결용으로 사용중이다.
1. Main 스토리보드에 VC를 하나 만들어준다.
- 이후 구현하게될 클래스명을 SearchViewController로 칭하게될 예정이여서 클래스명을 동일하게 설정해둔다.

2. 만들어 놓은 SeachViewController를 Navigation Controller에 Embed 해준다
우리는 navigationItem에 searchBar를 넣어줄거기 때문에 Embed를 미리 해주어야 한다.

3. Model을 따로 구조체로 만들어준다
- 모델은 데이터이므로 배열에 검색시에 나올데이터에 정의를 해두었다.( 추후 API통신으로 서버에 있는 데이터를 불러올 예정이다.)
- filterValue같은경우는 우리가 한글자 입력할때마다 해당 빈배열에 한글자씩 들어오게하려고 정의를 해두었다.
- Codable로 선언해둔 이유는 나중에 API를 통해 받을데이터 타입이 Json이기 때문에 선언해주었다.
Codable에 대해서 따로 확인이 필요하면 정리한 블로그가 존재한다. https://yoonds-develop.tistory.com/13
struct DestiData: Codable {
static let shared = DestiData(place: "")
let place: String
var filterValue: Array<String> = []
let placeData: Array<String> = ["강남", "강기도", "강원도", "서울시", "서강시"]
init(place: String) {
self.place = place
}
}
4. Cocoa Touch Class를 통하여 UIViewController를 서브로 두는 SeachViewController를 생성해주자

5. 해당 클래스 내부에 searchBar변수를 생성해준다.
- .obscuresBackgroundDuringPresentation는 검색바 선택시에 해당외에 나머지는 어둡게할건지? false를 주게되면 밝게 가저갑니다.
- .searchController = searchController 이부분이 핵심입니다. 우측의 생성해준 객체를
navigationItem의 searchController로 넣어줌으로써 생성된 객체가 SearchViewController의 서치바로 등록이 된것입니다. - .prefersLargeTitles는 title을 큰title로 등록할건지에 대한 속성입니다.
- .hidesSearchBarWhenScrolling는 스크롤시에 searchBar부분을 유지할것인지, 숨길것인지에 대한 속성입니다.
lazy var userSearchBar: UISearchController = {
let searchController = UISearchController()
searchController.searchBar.placeholder = "목적지를 입력해주세요"
searchController.obscuresBackgroundDuringPresentation = false
self.navigationItem.searchController = searchController
self.navigationItem.title = "목적지 검색"
self.navigationController?.navigationBar.prefersLargeTitles = true
self.navigationItem.hidesSearchBarWhenScrolling = false
return searchController
}()
6. 데이터가 노출될 테이블이 필요하니 테이블을 생성해준다.
- register를 등록하여 이테이블에 대한 이름을 지정해준다 "dataCell"
lazy var serachDataTable: UITableView = {
let tableView = UITableView()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "dataCell")
return tableView
}()
7. 모델의 데이터 미리보여주기
- 위에서 만들어둔 userSearchBar객체가 active(타이핑 등)중이면서 Text가 비어있지 않으면 true 그렇지 않다면 false를 반환한다.
var filterCheck: Bool {
let searchController = self.navigationItem.searchController
let isActive = searchController?.isActive ?? false
let isEmpty = searchController?.searchBar.text?.isEmpty ?? false
return isActive && isEmpty
}
8. 테이블에 대한 레이아웃잡기
- 스냅킷을 활용하여 Layout을 잡고있어서 스냅킷 import가 필요하다
"스냅킷 관련하여 다룰 블로그가 등록될 예정" - .multipliedBy(1.0).offset(0) 이 부분은 1.0배수, 0이기때문에 생략하여도 상관없지만
레이아웃 잡을대 항상 등록했던 옵션이여서 습관적으로 만들어 두었다.
func setLayout() {
placeDataTable.snp.makeConstraints {
$0.top.equalToSuperview().multipliedBy(1.0).offset(0)
$0.leading.equalToSuperview().multipliedBy(1.0).offset(0)
$0.bottom.equalToSuperview().multipliedBy(1.0).offset(0)
$0.right.equalToSuperview().multipliedBy(1.0).offset(0)
}
}
9. 생성해둔 클래스에서 Delegate사용을 위해 프로토콜 채택을 진행한다.
- UISearchResultsUpdating, UITableViewDataSource
class SearchViewController: UIViewController, UISearchResultsUpdating, UITableViewDataSource
10. 채택을 진행하게되면 필수 메소드를 구현하라고 한다.
- 작성자인 내가 만들고 싶어서 만든 함수명이 아닌 프로토콜에서 이미 정의된 함수명이다.
해당 updateSearchResults함수는 서치바에서 한글자 칠때마다 실행되는 함수이다. - print로 보다시피 한글자 입력시마다 함수가 실행되어 글자가 찍히게 된다
- .reloadData 유저가 글자를 입력할때마다 테이블을 불러와 해당값에 대한 내용을 보여준다.
func updateSearchResults(for placeSearch: UISearchController) {
guard let userText = placeSearch.searchBar.text
else {
return
}
print("사용자 입력 : ", userText )
self.data.filterValue = self.data.placeData.filter{
$0.localizedCaseInsensitiveContains(userText)}
self.placeDataTable.reloadData()
}

11. table의 numberOfRowsInSection으로 몇개의 cell을 생성할건지 정해준다.
- 3항연산을 활용하여 filterCheck시에 true(내가 지금 타이핑 중)이면 filterValue수 만큼
- false(건들지않은 상태)이면 전체 데이터를 보여줘야하니 placeData 수만큼 cell을 생성해준다.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.filterCheck ? self.data.filterValue.count : self.data.placeData.count
}
12. table의 cellForRowAt으로 어떤 데이터를 활용하여 테이블을 구현할건지 정의 한다.
- 미리 객체로 만들어둔 placeDataTable을 활용할것이다.
- 어떤 테이블을 사용할거야? 미리 "dataCell"로 정의했던 table을 지정해준다.
- 이후 false(건들지않은 상태)일때 Model안에 있는 배열 데이터를 cell의 textLabel에 넣어 찍어준다.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "dataCell")!
if self.filterCheck == false {
cell.textLabel?.text = self.data.placeData[indexPath.row]
} else {
cell.textLabel?.text = self.data.filterValue[indexPath.row]
}
return cell
}
전체코드
import UIKit
import SnapKit
class SearchViewController: UIViewController, UISearchResultsUpdating, UITableViewDataSource {
lazy var userSearchBar: UISearchController = {
let searchController = UISearchController()
searchController.searchBar.placeholder = "목적지를 입력해주세요"
// 검색이후 나머지뷰 어둡게?
searchController.obscuresBackgroundDuringPresentation = false
// searchController를 navi의 searchController에 넣어줘야함
self.navigationItem.searchController = searchController
self.navigationItem.title = "목적지 검색"
self.navigationController?.navigationBar.prefersLargeTitles = true
self.navigationItem.hidesSearchBarWhenScrolling = false
return searchController
}()
lazy var placeDataTable: UITableView = {
let tableView = UITableView()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "dataCell")
return tableView
}()
var data: DestiData = DestiData(place: "")
var filterCheck: Bool {
let searchController = self.navigationItem.searchController
let isActive = searchController?.isActive ?? false
let isEmpty = searchController?.searchBar.text?.isEmpty ?? false
return isActive && isEmpty
}
override func viewDidLoad() {
super.viewDidLoad()
setUpView()
setDelegate()
setLayout()
}
func setUpView() {
view.addSubview(placeDataTable)
}
func setDelegate() {
placeDataTable.dataSource = self
userSearchBar.searchResultsUpdater = self
}
func setLayout() {
placeDataTable.snp.makeConstraints {
$0.top.equalToSuperview().multipliedBy(1.0).offset(0)
$0.leading.equalToSuperview().multipliedBy(1.0).offset(0)
$0.bottom.equalToSuperview().multipliedBy(1.0).offset(0)
$0.right.equalToSuperview().multipliedBy(1.0).offset(0)
}
}
// delegate 관련 메소드
// 서치바에서 검색시마다 해당 메소드 실행
func updateSearchResults(for placeSearch: UISearchController) {
guard let userText = placeSearch.searchBar.text
else {
return
}
print("사용자 입력 : ", userText )
self.data.filterValue = self.data.placeData.filter{ $0.localizedCaseInsensitiveContains(userText)}
self.placeDataTable.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//3항연산으로 filterValue에 값이 있으면 반환, 없으면 items를 반환
return self.filterCheck ? self.data.filterValue.count : self.data.placeData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "dataCell")!
if self.filterCheck == false {
cell.textLabel?.text = self.data.placeData[indexPath.row]
} else {
cell.textLabel?.text = self.data.filterValue[indexPath.row]
}
return cell
}
}
개인학습 목적으로 이해, 공부하면 정리한 내용이라 미숙한점이 있을수도 있다.
태클, 문의사항 언제든 환영
'Swift(IOS)' 카테고리의 다른 글
| [내용정리] Swift - closure(클로저)란? (1/2) (0) | 2022.02.03 |
|---|---|
| [내용정리] Swift - UITableVIew Delegate, DataSource 종류 (0) | 2022.01.26 |
| [내용정리] Swift - URLSession 이란? (0) | 2022.01.11 |
| [오류처리] Swift - Add a new account in the Accounts preference pane or verify that your accounts have valid credentials. (0) | 2022.01.04 |
| [내용정리] Swift - Delegate란? (3) | 2022.01.04 |