[Do it!] 맵 뷰 앱

CoCoral·2023년 9월 19일
1

Do it!

목록 보기
12/25
post-thumbnail

Do it! 스위프트로 아이폰 앱 만들기
08장 맵 뷰로 지도 나타내기

📱 실행 화면 📱


💻 Step 1. 필요한 객체 배치하기

세그먼트 컨트롤 배치하고 세그먼트 수와 타이틀 변경하기
Library(+) 에서 Map Kit View 를 찾아 배치하기
Label 2개 배치하기


💻 Step 2. Outlet 변수, Action 함수 추가하기

맵 킷 뷰에 대한 아웃렛 변수 추가하기
import MapKit 추가하기
💡Map Kit: 지도 확대, 축소, 이동 등 지도 관련 기능 제공
레이블 2개에 대한 아웃렛 변수 추가하기
세그먼트 컨트롤에 대한 액션 함수 추가하기


💻 Step 3. 지도 보여주기

class ViewController: UIViewController, CLLocationManagerDelegate {
    @IBOutlet var myMap: MKMapView!
    @IBOutlet var lblLocationInfo1: UILabel!
    @IBOutlet var lblLocationInfo2: UILabel!

    let locationManager = CLLocationManager()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        lblLocationInfo1.text = ""
        lblLocationInfo2.text = ""
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestWhenInUseAuthorization()
        locationManager.startUpdatingLocation()
        myMap.showsUserLocation = true
    }
  • CLLocationManagerDelegate 상속하기
  • locationManager 선언하기
  • 레이블의 텍스트를 빈 값으로 설정하기
  • locationManager 의 delegate 값을 self(뷰 컨트롤러)로 설정하기
  • 위치 정확도를 최고로 설정하기
  • 위치 데이터를 추적하기 위해 사용자에게 승인 요구하기
  • 위치 업데이트 시작하기
  • 위치 보기 값을 true 로 설정하기

  • Info의 Information Property List 에 Privacy - Location When In Use Usage Description 을 추가하고 Value 수정하기

💻 Step 4. 위도와 경도로 원하는 위치 표시하기

func goLocation(latitudeValue: CLLocationDegrees, longitudeValue: CLLocationDegrees, delta span: Double) {
        let pLocation = CLLocationCoordinate2DMake(latitudeValue, longitudeValue)
        let spanValue = MKCoordinateSpan(latitudeDelta: span, longitudeDelta: span)
        let pRegion = MKCoordinateRegion(center: pLocation, span: spanValue)
        myMap.setRegion(pRegion, animated: true)
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let pLocation = locations.last
        goLocation(latitudeValue: (pLocation?.coordinate.latitude)!, longitudeValue: (pLocation?.coordinate.longitude)!, delta: 0.01)
    }
  • pLocation: 위도와 경도를 CLLocationCoordinate2D 구조체로 변환하기
  • spanValue: 지도 영역의 너비 및 높이를 설정하기
  • pRegion: pLocation 과 spanValue 를 결합하여 지도 영역을 생성하기
  • pRegion 을 myMap 에 설정하기
  • 사용자의 업데이트된 현재 위치에 따라 지도 영역 업데이트하기

💻 Step 5. 위치 정보 추출해 텍스트로 표시하기

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let pLocation = locations.last
        goLocation(latitudeValue: (pLocation?.coordinate.latitude)!, longitudeValue: (pLocation?.coordinate.longitude)!, delta: 0.01)
        
        //추가 코드
        CLGeocoder().reverseGeocodeLocation(pLocation!, completionHandler: { (placemarks, error) in
            let pm = placemarks!.first
            let country = pm!.country
            var address: String = country!
            if pm!.locality != nil {
                address += " "
                address += pm!.locality!
            }
            if pm!.thoroughfare != nil {
                address += " "
                address += pm!.thoroughfare!
            }
            
            self.lblLocationInfo1.text = "현재 위치"
            self.lblLocationInfo2.text = address
        })
        
        locationManager.stopUpdatingLocation()
    }
  • pLocation 에 담긴 위도, 경도 정보를 통해 주소로 변환하는 메소드를 추가한다.
  • pm 에는 placemarks 의 첫번째 요소(가장 정확한 주소 정보)만 가져온다.
  • 문자열 address 에 나라 값을 추가한다.
  • 지역 값이 존재하면 문자열에 추가한다.
  • 도로 값이 존재하면 문자열에 추가한다.
  • 레이블에 문자열 값을 표시한다.
  • 위치 업데이트를 중단시킨다.

💻 Step 6. 위도와 경도로 원하는 핀 설치하기

func setAnnotation(latitudeValue: CLLocationDegrees, longitudeValue: CLLocationDegrees, delta span: Double, title strTitle: String, subtitle strSubtitle: String) {
    let annotation = MKPointAnnotation()
    annotation.coordinate = goLocation(latitudeValue: latitudeValue, longitudeValue: longitudeValue, delta: span)
    annotation.title = strTitle
    annotation.subtitle = strSubtitle
    myMap.addAnnotation(annotation)
}
  • annotation 의 coordinate 에 위치 정보를 설정하기 위해 goLocation 함수의 반환형을 CLLocationCoordinate2D, 반환값을 pLocation 으로 설정하기
@IBAction func sgChangeLocation(_ sender: UISegmentedControl) {
    if sender.selectedSegmentIndex == 0 {
        self.lblLocationInfo1.text = ""
        self.lblLocationInfo2.text = ""
        locationManager.startUpdatingLocation()
    }
    else if sender.selectedSegmentIndex == 1 {
        setAnnotation(latitudeValue: 37.555878, longitudeValue: 126.972295, delta: 0.01, title: "서울역", subtitle: "서울특별시 중구 소공동 세종대로18길 2")
        self.lblLocationInfo1.text = "보고 계신 위치"
        self.lblLocationInfo2.text = "서울역"
    }
    else {
        setAnnotation(latitudeValue: 37.551848, longitudeValue: 127.073638, delta: 0.01, title: "세종대학교", subtitle: "서울특별시 광진구 능동로 209 세종대학교")
        self.lblLocationInfo1.text = "보고 계신 위치"
        self.lblLocationInfo2.text = "세종대학교"
    }
}
  • 세그먼트 컨트롤에서 현재 위치를 터치했을 때 위치 업데이트 시작하기
  • 두번째, 세번째 세그먼트를 터치했을 때 핀 설치하기

💻 Final Step. ViewController.swift 전체 소스 코드

import UIKit
import MapKit

class ViewController: UIViewController, CLLocationManagerDelegate {
    @IBOutlet var myMap: MKMapView!
    @IBOutlet var lblLocationInfo1: UILabel!
    @IBOutlet var lblLocationInfo2: UILabel!

    let locationManager = CLLocationManager()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        lblLocationInfo1.text = ""
        lblLocationInfo2.text = ""
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestWhenInUseAuthorization()
        locationManager.startUpdatingLocation()
        myMap.showsUserLocation = true
    }
    
    func goLocation(latitudeValue: CLLocationDegrees, longitudeValue: CLLocationDegrees, delta span: Double) -> CLLocationCoordinate2D {
        let pLocation = CLLocationCoordinate2DMake(latitudeValue, longitudeValue)
        let spanValue = MKCoordinateSpan(latitudeDelta: span, longitudeDelta: span)
        let pRegion = MKCoordinateRegion(center: pLocation, span: spanValue)
        myMap.setRegion(pRegion, animated: true)
        return pLocation
    }
    
    func setAnnotation(latitudeValue: CLLocationDegrees, longitudeValue: CLLocationDegrees, delta span: Double, title strTitle: String, subtitle strSubtitle: String) {
        let annotation = MKPointAnnotation()
        annotation.coordinate = goLocation(latitudeValue: latitudeValue, longitudeValue: longitudeValue, delta: span)
        annotation.title = strTitle
        annotation.subtitle = strSubtitle
        myMap.addAnnotation(annotation)
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let pLocation = locations.last
        _ = goLocation(latitudeValue: (pLocation?.coordinate.latitude)!, longitudeValue: (pLocation?.coordinate.longitude)!, delta: 0.01)
        CLGeocoder().reverseGeocodeLocation(pLocation!, completionHandler: { (placemarks, error) in
            let pm = placemarks!.first
            let country = pm!.country
            var address: String = country!
            if pm!.locality != nil {
                address += " "
                address += pm!.locality!
            }
            if pm!.thoroughfare != nil {
                address += " "
                address += pm!.thoroughfare!
            }
            
            self.lblLocationInfo1.text = "현재 위치"
            self.lblLocationInfo2.text = address
        })
        
        locationManager.stopUpdatingLocation()
    }

    @IBAction func sgChangeLocation(_ sender: UISegmentedControl) {
        if sender.selectedSegmentIndex == 0 {
            self.lblLocationInfo1.text = ""
            self.lblLocationInfo2.text = ""
            locationManager.startUpdatingLocation()
        }
        else if sender.selectedSegmentIndex == 1 {
            setAnnotation(latitudeValue: 37.555878, longitudeValue: 126.972295, delta: 0.01, title: "서울역", subtitle: "서울특별시 중구 소공동 세종대로18길 2")
            self.lblLocationInfo1.text = "보고 계신 위치"
            self.lblLocationInfo2.text = "서울역"
        }
        else {
            setAnnotation(latitudeValue: 37.551848, longitudeValue: 127.073638, delta: 0.01, title: "세종대학교", subtitle: "서울특별시 광진구 능동로 209 세종대학교")
            self.lblLocationInfo1.text = "보고 계신 위치"
            self.lblLocationInfo2.text = "세종대학교"
        }
    }
}

✏️ 개념 알고가기

  • locationManager.delegate = self
    - delegate 설정을 하지 않으면 위치 업데이트 이벤트 처리, 위치 권한 요청, 위치 데이터 수집이 불가능하다.

  • locationManager(_ manager: didUpdateLocations locations: )
    - 사용자의 현재 위치 업데이트를 감지하였을 때 실행된다.

profile
언젠간 iOS 개발자가 되겠지

2개의 댓글

comment-user-thumbnail
2023년 9월 21일

미국 뭐에요 ㅋㅋ

1개의 답글