이번 글에서 만들어 보고자 하는 것은 MapKit을 사용하여 지도의 임의의 위치를 클릭했을 때 해당 위치의 주소를 추출해 보는 App을 만들어 보겠습니다. 일일이 주소를 입력해서 찾는 것보다 그 위치를 한 번의 클릭만으로 주소를 얻어 보고 싶을 때 한 번 사용해보면 좋을 것 같습니다.
특별한 알고리즘을 사용하지 않기 때문에 만드는 데는 큰 어려움은 없습니다.
1. 디자인
저는 간단히 MapView하나와 추출된 주소를 표시할 수 있는 라벨, 이 두 가지만 추가해 보았습니다.
2. 베이스 작성
맵의 임의의 위치를 클릭 했을 때이기 때문에 맵을 클릭할 수 있어야 합니다.
때문에 저는 Tap 제스처를 추가하였습니다.
import UIKit
import MapKit
class ViewController: UIViewController {
@IBOutlet weak var mapView: MKMapView!
@IBOutlet weak var locationLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
self.initView()
}
private func initView() {
// 맵에 Tap 제스처를 추가합니다.
let tap = UITapGestureRecognizer(target: self, action: #selector(self.didTappedMapView(_:)))
self.mapView.addGestureRecognizer(tap)
}
}
//
// MARK:- 맵을 터치 했을 때
//
extension ViewController {
/// 제스처 동작
@objc
private func didTappedMapView(_ sender: UITapGestureRecognizer) {
// TODO: 제스처 동작
}
}
3. 위치 탐색
탐색은 Geocoder의 역 탐색을 사용합니다.
/// 제스처 조작
@objc
private func didTappedMapView(_ sender: UITapGestureRecognizer) {
let location: CGPoint = sender.location(in: self.mapView) // 클릭 위치를 취득
let mapPoint: CLLocationCoordinate2D = self.mapView.convert(location, toCoordinateFrom: self.mapView) // 해당 위치를 location으로 변환
if sender.state == .ended {
// 탐색 스타트
self.searchLocation(mapPoint)
}
}
/// 해당 포인트의 주소를 검색
private func searchLocation(_ point: CLLocationCoordinate2D) {
let geocoder: CLGeocoder = CLGeocoder()
let location = CLLocation(latitude: point.latitude, longitude: point.longitude)
geocoder.reverseGeocodeLocation(location) { (placeMarks, error) in
if error == nil, let marks = placeMarks {
marks.forEach { (placeMark) in
let annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2D(latitude: point.latitude, longitude: point.longitude)
self.locationLabel.text =
"""
\(placeMark.administrativeArea ?? "")
\(placeMark.locality ?? "")
\(placeMark.thoroughfare ?? "")
\(placeMark.subThoroughfare ?? "")
"""
self.mapView.addAnnotation(annotation)
}
} else {
self.locationLabel.text = "검색 실패"
}
}
}
추출하고 싶은 데이터는 아래와 같은 항목이 있습니다. 원하시는 데이터를 출력하시면 될 것 같습니다.
4. 전체 코드
이번 예시에서는 하나만의 위치만을 나타내기 위하여 포인트의 삭제도 구현하였습니다.
import UIKit
import MapKit
class ViewController: UIViewController {
@IBOutlet weak var mapView: MKMapView!
@IBOutlet weak var locationLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
self.initView()
}
private func initView() {
let tap = UITapGestureRecognizer(target: self, action: #selector(self.didTappedMapView(_:)))
self.mapView.addGestureRecognizer(tap)
}
}
//
// MARK:- 맵을 터치 했을 때
//
extension ViewController {
/// 제스처 조작
@objc
private func didTappedMapView(_ sender: UITapGestureRecognizer) {
let location: CGPoint = sender.location(in: self.mapView)
let mapPoint: CLLocationCoordinate2D = self.mapView.convert(location, toCoordinateFrom: self.mapView)
if sender.state == .ended {
self.searchLocation(mapPoint)
}
}
/// 하나만 출력하기 위하여 모든 포인트를 삭제
private func removeAllAnnotations() {
let allAnnotations = self.mapView.annotations
self.mapView.removeAnnotations(allAnnotations)
}
/// 해당 포인트의 주소를 검색
private func searchLocation(_ point: CLLocationCoordinate2D) {
let geocoder: CLGeocoder = CLGeocoder()
let location = CLLocation(latitude: point.latitude, longitude: point.longitude)
// 포인트 리셋
self.removeAllAnnotations()
geocoder.reverseGeocodeLocation(location) { (placeMarks, error) in
if error == nil, let marks = placeMarks {
marks.forEach { (placeMark) in
let annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2D(latitude: point.latitude, longitude: point.longitude)
self.locationLabel.text =
"""
\(placeMark.administrativeArea ?? "")
\(placeMark.locality ?? "")
\(placeMark.thoroughfare ?? "")
\(placeMark.subThoroughfare ?? "")
"""
self.mapView.addAnnotation(annotation)
}
} else {
self.locationLabel.text = "검색 실패"
}
}
}
}
5. 마무리
한 번 아무 위치나 클릭해보시면 해당 위치의 정보가 출력되는 것을 확인하실 수 있습니다.
궁금하신 점이나 지적 사항이 있으신 분은 댓글에 부탁드립니다.
많은 도움이 되었으면 좋겠습니다.
https://developer.apple.com/documentation/corelocation/clgeocoder/1423621-reversegeocodelocation
reverseGeocodeLocation(_:completionHandler:) - CLGeocoder | Apple Developer Documentation
Instance Method reverseGeocodeLocation(_:completionHandler:) Submits a reverse-geocoding request for the specified location. DeclarationParameterslocationThe location object containing the coordinate data to look up.completionHandlerThe handler block to ex
developer.apple.com
환경
Xcode 11.3.1
Swift 5
'Swift > 정보 공유' 카테고리의 다른 글
[Swift] UIActivityController에 대하여 알아보자! (0) | 2020.06.08 |
---|---|
[Swift] DispatchTimer를 사용해보자! (0) | 2020.06.05 |
[Swift] Set에 대하여 (0) | 2020.05.12 |
[Swift] Swift - 싱글톤 패턴(Singleton) (0) | 2020.05.08 |
[Swift] UICollectionView에 .xib커스텀 셀을 적용해보기 (0) | 2020.03.15 |