[새싹 iOS] 17주차_MapKit 실시간 장소 검색 및 Apple Map 위치 표시

임승섭·2024년 2월 17일
0

새싹 iOS

목록 보기
33/45

구현

실시간 장소 검색Apple Map Annotation

1. 실시간 장소 검색

View

  • 검색할 텍스트를 입력할 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

  • searchBar에 실시간으로 텍스트가 입력될 때마다
    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)
            }
        }

2. Apple Map 위치 표시

Model

  • 장소 정보에 대한 구조체
    struct TourLocation: Codable {
        let name: String
        let address: String
        let latitude: Double
        let longtitude: Double
    }

View

  • 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)
    }
    

레퍼런스

0개의 댓글