실시간 장소 검색 | Apple Map Annotation |
검색할 텍스트를 입력할 searchBar, 결과를 나타낼 tableView
let searchBar = {
let view = UISearchBar()
view.placeholder = "떠나고 싶은 장소를 검색하세요"
view.backgroundImage = UIImage()
view.searchTextField.backgroundColor = UIColor.appColor(.inputGray)
return view
}()
let tableView = {
let view = UITableView(frame: .zero, style: .plain)
view.register(SelectLocationTableViewCell.self, forCellReuseIdentifier: "SelectLocationTableViewCell")
view.rowHeight = 66
view.separatorInset = UIEdgeInsets(top: 0, left: 18, bottom: 0, right: 18)
view.contentMode = .scaleAspectFill
return view
}()
searchCompleter
: 입력한 문자열에 대해 해당되는 장소를 검색
searchResults
: 검색 결과 장소 배열 저장
localSearch
: 검색된 장소의 정보 저장
private var searchCompleter = MKLocalSearchCompleter()
private var searchResults = [MKLocalSearchCompletion]()
private var localSearch: MKLocalSearch? = nil {
willSet {
localSearch?.cancel()
}
}
setting
delegate 설정
func settingSearch() {
mainView.searchBar.delegate = self
searchCompleter.delegate = self
searchCompleter.resultTypes = .pointOfInterest
}
func settingTableView() {
mainView.tableView.delegate = self
mainView.tableView.dataSource = self
}
UITableViewDataSource
searchResults
의 요소를 테이블뷰에 나타냄
extension SelectLocationViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchResults.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "SelectLocationTableViewCell", for: indexPath) as? SelectLocationTableViewCell else { return UITableViewCell() }
cell.titleLabel.text = searchResults[indexPath.row].title
cell.subTitleLabel.text = searchResults[indexPath.row].subtitle
return cell
}
}
UISearchBarDelegate
searchCompleter.queryFragment
에 텍스트를 넘겨주어서 해당하는 장소를 검색하도록 한다extension SelectLocationViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
// 서치바에 입력할 때마다 텍스트 넘겨주기
if searchText.count != 0 {
searchCompleter.queryFragment = searchText
}
}
}
MKLocalSearchCompleterDelegate
searchCompleter
의 장소 검색에 대한 결과
extension SelectLocationViewController: MKLocalSearchCompleterDelegate {
func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
searchResults = completer.results
mainView.tableView.reloadData()
}
func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) {
print("location 가져오기 에러 발생 : \(error.localizedDescription)")
}
}
UITableViewDelegate
셀을 클릭했을 때, 해당 장소에 대한 정보 전달 (delegate pattern)
extension SelectLocationViewController: UITableViewDelegate {
// MKLocalSearchCompletion 타입 데이터
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
search(for: searchResults[indexPath.row])
}
// searchRequest 생성
func search(for suggestedCompletion: MKLocalSearchCompletion) {
let searchRequest = MKLocalSearch.Request(completion: suggestedCompletion)
search(using: searchRequest)
}
// 장소 정보
func search(using searchRequest: MKLocalSearch.Request) {
searchRequest.resultTypes = .pointOfInterest // 검색 유형
localSearch = MKLocalSearch(request: searchRequest)
localSearch?.start { [weak self] (response, error) in
guard error == nil else { return }
guard let place = response?.mapItems[0] else { return }
// 데이터 전달하기 위해 필요한 정보 : 이름, 주소, 위도, 경도
let placeName = place.name ?? ""
let placeAddress = place.placemark.title ?? ""
let placeLatitude = Double(place.placemark.coordinate.latitude)
let placeLongtitude = Double(place.placemark.coordinate.longitude)
self?.delegate?.sendLocation?(
name: placeName,
address: placeAddress,
latitude: placeLatitude,
longitude: placeLongtitude
)
self?.navigationController?.popViewController(animated: true)
}
}
struct TourLocation: Codable {
let name: String
let address: String
let latitude: Double
let longtitude: Double
}
MKMapView
사용
// 뷰 객체 선언
let locationView = {
let view = MKMapView()
view.clipsToBounds = true
view.layer.cornerRadius = 10
return view
}()
// 뷰 업데이트
func setUpMapView(sender: TourLocation) {
// 위도, 경도 설정
let centerLocation = CLLocationCoordinate2D(
latitude: locationStruct.latitude,
longitude: locationStruct.longtitude
)
// 지도에 표시할 범위
let region = MKCoordinateRegion(
center: centerLocation,
latitudinalMeters: 100,
longitudinalMeters: 100
)
// annotation (pin 설정)
let annotation = MKPointAnnotation()
annotation.title = locationStruct.name
annotation.coordinate = centerLocation
// locationView 세팅
locationView.addAnnotation(annotation)
locationView.setRegion(region, animated: true)
}