👥Club/🍀UMC🍀

🍎 5주차 - 지도

비엔 Vien 2025. 4. 29. 01:23

후후 이번에는 직접 쓰려고 꽤나 노력을 햇슴다 ^^

그리고 나 이거 폰으로 안 뜨는데? ㅋ 뭔 오류나는디 > 일단 영상 있으니게,,, 그걸로 확인 ㄱ

 

CoreLocation 프레임 워크

위치 기반

- GPS로 현재 위치 파악

- 실시간 위치 업뎃

- 지오펜싱

- 방향 감지

 

____________________

 

MapKit

지도에 위치를 시각화하고 상호작용하는 기능

(지도 데이터 + 위치 시각화 + 사용자 인터렉션)

import SwiftUI
import MapKit

struct ContentView: View {
    
    @State var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 37.5665, longitude: 126.9780), span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05))
    
    var body: some View {
        Map(initialPosition: .region(region))
    }
}

#Preview {
    ContentView()
}

 

- MKCoordinateRegion : 지도에서 보여줄 영역(중심 좌표 + 줌 정도)

- Map : SwiftUI의 지도 컴포넌트 ( UIKit의 MKMapView 역할) & Deprecated  조심하라는데?

- CLLocationCoordinate2D : 위도(latitude), 경도 (longitude)

 

+ Info.plist에 위치 권한 설정하라는데

( 앱이 위치 정보 사용하기 위해서는 반드시 사용자에게 권한 요청해야함 )

Info.plist 파일에 권한 사용 목적을 명시하는 문자열을 추가해야...

<key>NSLocationWhenInUseUsageDescription</key>
<string>이 앱은 현재 위치를 표시하기 위해 위치 정보가 필요합니다.</string>

 


(여기는 출처 유엠씨 학습자료? 암튼 그거) 

 

[ 지도 사용 용어 정리(지도에서 사용되는 개념 자체 용어) ]

 

위도 (Latitude) 지구를 가로로 나눈 좌표. 북위(N)와 남위(S)로 구분 서울: 37.5665°N
경도 (Longitude) 지구를 세로로 나눈 좌표. 동경(E)과 서경(W)로 구분 서울: 126.9780°E
고도 (Altitude) 해수면으로부터의 높이. 단위는 보통 미터(m) 한라산 정상: 약 1,947m
좌표 (Coordinate) 위도 + 경도로 구성된 위치의 정확한 좌표 CLLocationCoordinate2D(latitude: 37.5665, longitude: 126.9780)
방향 (Heading) 사용자가 보고 있는 방향. 나침반 각도(0~360°) 북쪽: 0°, 동쪽: 90°
줌 레벨 (Zoom Level) 지도를 얼마나 확대/축소할지를 나타내는 값. 수치가 낮을수록 더 확대됨 지도 전체 보기: 줌 2, 건물 보기: 줌 18
지도 중심 (Map Center) 현재 지도의 정중앙 좌표 서울역이 화면 가운데에 보일 경우: 중심 좌표는 서울역
지오펜싱 (Geofence) 특정 반경 내에 사용자가 들어오거나 나갈 때 이벤트 발생 반경 100m 안으로 들어오면 알림 보내기
반경 (Radius) 지오펜싱에서 중심에서 바깥쪽까지의 거리. 단위는 미터(m) 반경 200m 설정
장소 (Place / POI) 지도에 등록된 특정 장소 정보 (Point of Interest) 스타벅스, 서울시청, CGV
경로 (Route / Path) 한 지점에서 다른 지점까지 이동하는 경로 집 → 학교까지 도보 경로
거리 (Distance) 두 위치 사이의 직선 거리 또는 경로 거리 집과 마트 사이: 700m
사용자 위치 (User Location) 현재 사용자의 위치 (GPS로 측정) 내 위치를 파란 점으로 표시
타겟 위치 (Target Location) 사용자가 가려는 목적지 좌표 “강남역으로 가는 길 안내”
지도 스타일 (Map Style) 지도에 보여지는 모양 또는 테마 일반 지도 / 위성 지도 / 하이브리드
터치 인터랙션 지도에서 사용자 터치에 따른 동작 핀 추가, 확대/축소, 위치 이동
영역 (Region) 지도에서 보여주는 위도/경도 범위 중심: 강남, 반경: 500m
스팬 (Span) 화면에서 보여줄 위도/경도의 확장 범위 latitudeDelta / longitudeDelta
트래킹 모드 (Tracking Mode) 사용자의 현재 위치를 따라갈지 여부 follow / none / followWithHeading
정확도 (Accuracy) 위치 측정의 정밀도 (낮을수록 정확함) GPS 모드: 수 미터 정확도
위치 권한 (Location Authorization) 위치 서비스를 사용할 수 있는 권한 상태 항상 허용 / 사용 중에만 허용 / 거부됨

 

 

[ 지도 사용 용어 정리(코드적인 개념) ]

MapKit 애플이 제공하는 지도 프레임워크. 지도를 화면에 표시하고, 핀을 추가하거나 위치를 추적할 수 있음
Map (SwiftUI) SwiftUI에서 지도 뷰를 표시할 때 사용하는 뷰. Map(position:) 등의 형태로 사용
MKMapView (UIKit) UIKit에서 지도 화면을 표시하는 뷰 클래스. SwiftUI의 Map과 대응되는 UIKit 버전
CLLocationManager 사용자의 현재 위치를 감지하고 추적하는 객체. GPS나 Wi-Fi, 셀룰러 네트워크 등을 사용함
CLLocation 위도, 경도, 고도 등의 정확한 위치 정보를 담고 있는 객체
CLLocationCoordinate2D 위도(latitude)와 경도(longitude)로 구성된 2차원 위치 좌표 구조체
MapCameraPosition(SwiftUI) SwiftUI 5에서 지도 카메라 위치를 제어할 때 사용하는 타입. .region(...), .automatic 등으로 설정
MKCoordinateRegion 지도에서 보여줄 중심 좌표와 확대 수준(줌)을 지정하는 영역. 카메라 위치 설정에 사용
MKCoordinateSpan 지도에서 가로/세로 방향으로 얼마나 확대해서 보여줄지를 정하는 값. 작을수록 확대됨
MapAnnotation SwiftUI에서 지도에 커스텀 뷰를 추가할 수 있는 핀. 예: 텍스트나 이미지로 표시 가능
MapMarker SwiftUI에서 기본 제공되는 핀 형태. 빨간색 마커로 표시됨. 간단한 마커가 필요할 때 사용
Annotation (UIKit) 지도에 표시하는 마커를 총칭. MKPointAnnotation 등의 객체로 추가함
MapCamera (UIKit) MKMapView에서 카메라 위치, 고도, 각도 등을 세밀하게 조정할 수 있는 객체
Region 지도의 중심 좌표와 범위를 함께 나타내는 개념. MKCoordinateRegion으로 표현
Span 지도를 얼마나 확대할지를 결정하는 값. latitudeDelta, longitudeDelta 값으로 줌 조절
Heading 사용자의 기기 방향(나침반 방향). 동서남북 중 어디를 보고 있는지를 의미함
TrackingMode 지도가 사용자의 위치를 따라갈지 말지를 설정하는 모드. 예: follow, none, followWithHeading 등
Geofence 특정 위치를 중심으로 반경을 설정하고, 출입 여부를 감지하는 기술. 위치 기반 알림 등에 사용
Visit Monitoring 사용자가 특정 장소에 일정 시간 머물렀다 떠날 때 자동으로 감지하는 기능. 저전력 기반
Significant Location Change 수백 미터 이상 이동했을 때만 위치 업데이트를 받는 모드. 배터리 효율이 좋음
Location Authorization 위치 권한 설정. WhenInUse, Always, Denied 등으로 나뉘며 Info.plist 설정이 필요함

 


(여기도 출처 유엠씨 학습자료? 암튼 그거) 

 

8자리로 하라는 말씀이신가요 그러니까??? ㄴㄴ 4자리 이상인듯 암튼 

 

  • 일반적인 권장 정밀도입니다.

소수점 자리수위치 정확도

3자리  110m 정도
4자리  11m 정도 (건물 단위)
5자리  1.1m 정도 (사람 크기)
6자리  11cm (보행자 위치, 자율주행)
7자리  1.1cm
8자리  1mm ~ 1.1mm
  • 실전에서 자주 쓰는 소수점 자릿수
목적 권장 자리수 설명
일반적인 위치 표시 (핀, 지도 이동) 5~6자리 1미터 이내 정확도
차량/보행자 위치 추적 6~7자리 고정밀 필요
고정된 장소 마킹 (카페, 관광지 등) 5자리 충분함
실내 위치 / 자율주행 / 측량 7~8자리 고정밀 GPS 필요

 

 

서버와 작업하는데 프론트가 서버에 8자리로 위도 / 경도 보내고 어느 부분에 다시 위도 / 경도 값을 돌려 받는다고 할 때 서버가 소수점 4자리 이상으로 안 준다??

바로 몽둥이 🏏 휘두르면 됩니다.

    ㄴ 뭐야?;


 

지도는 그리드

 

let xTile = floor((longitude + 180.0) / 360.0 * pow(2.0, z))
let yTile = floor((1.0 - log(tan(latitude * .pi / 180.0) + 1.0 / cos(latitude * .pi / 180.0)) / .pi) / 2.0 * pow(2.0, z))

위 수식 외우지 말라는디


 

계산된 X/Y 타일 번호를 서버에 요청

⬇️

서버로부터 블라블라.png 파일로 받아와 렌더링

⬇️

이 블라블라.png 타일이 지도위에 올라가서 배경이 그려지고 이 위에 현재 위치 마커 등등 인터페이스들을 갖춤

⬇️

근데 지도에 서울시청만 딱 하나 있을리가 없음

실제로 타일을 받아온다면, 보통 그 중심을 포함한 상하좌우 몇 장씩의 타일을 함께 불러와서 렌더링

 

지도 앱이 어쩔 때는 빠르고 어쩔 때는 느린지  

  • 타일은 개별 이미지다!! → 개별 이미지의 타일을 여러 장 요청해서 지도위에 그린다
  • 이동하거나 확대하면??? → 또 다시 타일 이미지를 요청하고 렌더링
  • 네트워크가 느리다면?? → 지도가 회색되거나 흰색되거나 등등 흐리게 뜬다

 


 

지도 위에 정보를 덧붙이는 방식인 '오버레이'

- 지도를 배경으로 하고, 그 위치에 추가적인 정보나 시각적 요소를 덧붙이는 방식

: 지도를 단순한 배경에서 의미 있는 정보 전달 도구의 역할을 하는 레이어

  • 사용자가 검색한 장소에 마커를 띄우는 것
  • 사용자가 지나간 경로를 선으로 그리는 것
  • 반경 1km 이내에 매장 보기 기능에서 원이 표시되는 것
  • 특정 지역을 음영 처리하는 것
종류 설명 예시
Marker / Annotation 특정 좌표에 핀이나 마커 추가 “서울역”에 마커 찍기
Polyline 여러 점을 선으로 연결 길 안내, 이동 경로 표시
Polygon 여러 점을 닫힌 선으로 연결한 면 구역 표시, 서비스 지역 표시
Circle 중심과 반지름으로 정의된 원 반경 500m 표시, 지오펜싱
Custom Annotation View 이미지, 텍스트 등 커스텀 뷰 표시 사용자 프로필 핀, 커스텀 UI
Heatmap / Tile Overlay 특정 데이터 밀도, 온도, 사용자 수 등 시각화 인구 밀도, 혼잡도 표시 등

 

 

 

 


우리는 지도에서 오버레이를 잘 활용해야 합니다.!

왜냐하면 오버레이는 지도를 단순한 배경에서 **의미 있는 정보 전달 도구**의 역할을 하는 레이어이기 때문이죠!

시각적으로 정보를 부각하고, 사용자의 인지를 돕고, 때론 빠른 판단까지 가능하게 해줍니다!

UX 관점에서 오버레이는 좌표를 의미로 바꾸는 레이어입니다.

지금 위치 근처 카페 5개 → 뭐로 표현하실래요? 
: 각 카페 좌표에 마커 찍기

배달 가능 지역은 여기까지이다! → 뭐로 표현하실래요?
: 원형오버레이 (현재 내 위치를 중심으로 원으로 표시)

 

여기서 여기까지 이동 경로 → 뭐로 표현하실래요?
: 폴리라인으로 경로 그리기 (출발지 & 도착지 지정후 연결하여 이동 경로 ) 

 

3개의 질문에 대해 어떻게 표현하는 게 좋을지 📌 이번 주차에는 이런 내용을 학습했어요! 작성하세요

 

 


 

 

위치 정보는 GPS, 셀룰러, WiFi로 측정됨


 

 

 

SwiftUI에서 **CLLocationManager**를 ViewModel 또는 **ObservableObject(@Observable)**로 관리하는 것이 일반적입니다!! 일반적인 걸 넘어서서 그냥 필수입니다.!!

 

-> 뭔말인가

📍 좀 더 쉽게 풀어서

 

  • CLLocationManager는 아이폰 GPS 위치 정보를 가져오는 기능이야.
  • 근데 얘를 그냥 SwiftUI View 안에 막 넣어서 쓰면,
    • 메모리 관리가 엉망,
    • 위치 업데이트 알림 처리가 복잡,
    • SwiftUI의 상태 변화를 제대로 못 따라가.
  •  
  • 그래서 CLLocationManager를 ViewModel이나 ObservableObject로 따로 뽑아서 관리해야 해.
    • 그래야 SwiftUI랑 “자동으로 바인딩” 되고,
    • 뷰가 상태 변화를 깔끔하게 감지할 수 있어.

 

어 그래 지피티야 고맙다

 

 


 

LocationManager / MapViewModel / MapView

<세 가지로 나누는 이유>

책임 분리

- 각 객체가 하나의 일만 하도록 해서 가독성과 유지 보수 향상

재사용성

- ViewModel과 LocationManager는 여러 화면에서 재사용 가능

확장성

- 거리계산, 검색결과 반영 등 기능을 View에 영향 없이 확장 가능

생명 주기 독립적 유지

- 위치 추적이 끊기지 않고 연속성으로 가능, 객체 생명주기 명확히 관리 가능

 

 

1. LocationManager

디바이스의 GPS와 직접 통신해서 위치를 받아오는 객체

- 위치 추적 기능만 담당하는 별도의 객체로 분리

( 👨‍✈️ LocationManager: 현재 어디 있는지 알려주는 파일럿 )

 

예시 기능

  1. 위치 권한 요청
  2. 위치 정보 업데이트 감지
  3. 방향 정보 수진

 

 

2. MapViewModel

지도 화면이 어떻게 보여야 하는가?를 계산하고 결정하는 뇌

- 현재 위치, 특정 장소, 검색 결과 등 지도 이동을 제어하는 로직의 중심

( 🧭 MapViewModel: 지도를 어떻게 움직일지 계산하는 항법사 )

 

예시 기능

  1. 현재 위치로 지도 이동
  2. 특정 좌표로 줌 이동
  3. 마커 배열 관리

 

 

3. MapView

Map을 띄우고, ViewModel의 바인딩 상태를 보여주는 역할

- ViewModel의 데이터를 바인딩 해 뷰를 자동 업데이트

( 🗺️ MapView: 실제로 지도를 보여주는 모니터 )

 

예시 기능

  1. 지도 영역 바인딩
  2. Annotation 표시
  3. onChange, onAppear 등을 통한 이벤트 처리

 


 

LocationManager 생성 및 분석

import Foundation
import CoreLocation
import MapKit
import Observation

@Observable
class LocationManager: NSObject {
    
    static let shared = LocationManager()
    
    // MARK: - CLLocationManager
    let locationManager = CLLocationManager()
    
    // MARK: - Published Properties
    var currentLocation: CLLocation?
    var currentHeading: CLHeading?
    
    var currentSpeed: CLLocationSpeed = 0
    var currentDirection: CLLocationDirection = 0
    
    var authorizationStatus: CLAuthorizationStatus = .notDetermined
    
    var didEnterGeofence: Bool = false
    var didExitGeofence: Bool = false
    
    // MARK: - Init
    override init() {
        super.init()
        
        locationManager.delegate = self // 위치 정보나 방향이 바뀔때 자신에게 알려달라는 의미
        locationManager.desiredAccuracy = kCLLocationAccuracyBest // 위치 정보의 정확도 수준을 설정, 배터리 많이 소모
        locationManager.headingFilter = kCLHeadingFilterNone // 방향(나침반) 업데이트 민감도 설정
                                                            // 아주 작은 변화도 모두 반영
                                                            // 사용자가 핸드폰을 살짝 돌려도 방향 정보가 업데이트 됨
        
        requestAuthorization()
        startUpdatingLocation()
        //- 실시간 위치 추적 시작
        //- 호출 이후 **`locationManager(_:didUpdateLocations:)`** 델리게이트 메서드가 주기적으로 호출됨
        //- 위치 변경이 감지되면 자동으로 알려줌
        
        startUpdatingHeading()
        //- 기기의 나침반(방향 센서) 정보 수신 시작
        //- 호출 이후 locationManager(_:didUpdateHeading:) 메서드 호출
    }
    
    // MARK: - 권한 요청
    func requestAuthorization() {
        locationManager.requestWhenInUseAuthorization()
        locationManager.requestAlwaysAuthorization()
    }

    // MARK: - 위치 추적
    func startUpdatingLocation() {
        locationManager.startUpdatingLocation()
    }
    
    func stopUpdatingLocation() {
        locationManager.stopUpdatingLocation()
    }
    
    // MARK: - 방향 추적
    func startUpdatingHeading() {
        locationManager.startUpdatingHeading()
    }
    
    func stopUpdatingHeading() {
        locationManager.stopUpdatingHeading()
    }

    // MARK: - Significant Location Change
    func startMonitoringSignificantLocationChanges() {
        locationManager.startMonitoringSignificantLocationChanges()
    }
    
    func stopMonitoringSignificantLocationChanges() {
        locationManager.stopMonitoringSignificantLocationChanges()
    }
    
    // MARK: - 방문 감지
    func startMonitoringVisits() {
        locationManager.startMonitoringVisits()
    }

    // MARK: - 지오펜싱
    func startMonitoringGeofence(center: CLLocationCoordinate2D,
                                 radius: CLLocationDistance,
                                 identifier: String) {
        let region = CLCircularRegion(center: center,
                                      radius: radius,
                                      identifier: identifier)
        region.notifyOnEntry = true
        region.notifyOnExit = true
        
        locationManager.startMonitoring(for: region)
        print("Monitoring regions: \(locationManager.monitoredRegions)")
    }

    func stopMonitoringAllGeofences() {
        for region in locationManager.monitoredRegions {
            locationManager.stopMonitoring(for: region)
        }
    }
}

// MARK: - CLLocationManagerDelegate
extension LocationManager: CLLocationManagerDelegate {
    
    // 권한 변경 감지
    //사용자가 위치 권한을 승인/거부하거나 설정을 변경했을 때 호출
    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        authorizationStatus = manager.authorizationStatus
    }

    // 위치 업데이트 감지 (기본 위치 추적 + Significant Change)
    // didUpdateLocations : startUpdatingLocation() 호출 후, 위치가 변경될 때마다 반복적으로 호출됨
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let latest = locations.last {
            DispatchQueue.main.async {
                self.currentLocation = latest
                self.currentSpeed = max(latest.speed, 0)
            }
        }
    }

    // 방향 감지
    // didUpdateHeading : startUpdatingHeading()을 호출하면 방향(나침반) 값이 바뀔 때마다 호출됨
    func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
        DispatchQueue.main.async {
            self.currentHeading = newHeading
            self.currentDirection = newHeading.trueHeading > 0 ? newHeading.trueHeading : newHeading.magneticHeading
        }
    }

    // 방문 감지 (visit monitoring)
    // didVisit : - 사용자가 어떤 장소에 도착해서 일정 시간 머무르고 떠났을 때 호출
    //          : - 보통은 머무른  시간이 수 분 이상이고, 이동이 명확하게 감지될 경우 호출
    //          : - iOS 시스템이 자동으로 의미 있는 장소를 인식해서 감지함
    func locationManager(_ manager: CLLocationManager, didVisit visit: CLVisit) {
        print("방문 감지됨 - 좌표: \(visit.coordinate), 도착: \(visit.arrivalDate), 출발: \(visit.departureDate)")
    }

    // 지오펜싱: 진입
    // didEnterRegion : 사용자가 지정한 영역(CLCircularRegion) 안으로 들어갔을 때
    func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
        DispatchQueue.main.async {
            self.didEnterGeofence = true
            self.didExitGeofence = false
        }
    }

    // 지오펜싱: 이탈
    // didExitRegion : 사용자가 설정한 영역 밖으로 나갔을 때
    func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
        DispatchQueue.main.async {
            self.didEnterGeofence = false
            self.didExitGeofence = true
        }
    }

    // 오류 처리
    // didFailWithError : 위치 정보 요청 중 문제가 발생했을 때 호출됨
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print("위치 오류: \(error.localizedDescription)")
    }
}

 


 

Annotation

 

Marker 모델 → MapViewModel에 데이터 저장 → MapView에서 Map+Annotation으로 지도에 핀 뿌림

 


 

지피티 정리 굿

📌 @Namespace란 무엇인가요?

  • @Namespace는 **SwiftUI에서 뷰 간 애니메이션(특히 일관된 전환)**을 할 때 사용하는 속성 래퍼입니다.
  • 쉽게 말하면, “뷰들 사이에 연결 고리(공통된 공간) 를 만들어주는 거예요.
  • 이 공간을 이용하면, 다른 뷰로 이동하거나 변할 때 부드럽게 연결된 애니메이션을 만들 수 있습니다.

→ “이 뷰랑 저 뷰는 같은 그룹이야!”

→ SwiftUI가 알아서 자연스럽게 이어주는 개념

 

 

📌 Map에서 @Namespace를 왜 사용할까요?

  • SwiftUI의 MapKit 컴포넌트(Map) 는 내부적으로 복잡한 상태를 관리합니다.
  • 지도 안의 여러 요소들(마커, 유저 위치 버튼 등)을 조작할 때,
  • 그냥 연결만 하면 오작동하거나 스코프를 제대로 인식 못할 수 있어요.
  • 그래서 @Namespace로 하나의 “공통 스코프(mapScope)” 를 만들어줘서,
    • 지도 안에 있는 여러 요소들 (Map, UserAnnotation, MapUserLocationButton)이
    • 서로 같은 범위(scope) 안에서 동기화되게 작동하도록 하는 거예요.

 

간단히:
“지도와 지도 위 버튼이 서로 같은 공간(mapScope)을 공유해야 제대로 동작해!”

 

@Namespace는 여러 SwiftUI 뷰가 “같은 공간” 안에 있다는 걸 표시해서, 부드럽고 일관된 상태 변화나 애니메이션을 가능하게 해준다!

 

 


 

지오펜스

지도 위에 가상의 원(지역) 을 설정해놓고, 사용자가 그 안에 들어오거나 나가면 특정 이벤트를 발생시키는 기능

 

// MARK: - 지오펜싱
func startMonitoringGeofence(center: CLLocationCoordinate2D,
                             radius: CLLocationDistance,
                             identifier: String) {
    let region = CLCircularRegion(center: center,
                                  radius: radius,
                                  identifier: identifier)
    region.notifyOnEntry = true
    region.notifyOnExit = true
    
    locationManager.startMonitoring(for: region)
    print("Monitoring regions: \(locationManager.monitoredRegions)")
}

 

 

특정 좌표(center)  반경(radius) 지오펜스(가상 울타리, 원) 를 만들어서 locationManager 이 영역을 모니터링하도록 등록하는 함수

 

 

func stopMonitoringAllGeofences() {
    for region in locationManager.monitoredRegions {
        locationManager.stopMonitoring(for: region)
    }
}

 

 

현재 등록된 모든 지오펜스를 하나하나 꺼버리는 함수

 

 

<지오펜스 진입/이탈을 감지하는 부분>

// 지오펜싱: 진입
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
    DispatchQueue.main.async {
        self.didEnterGeofence = true
        self.didExitGeofence = false
    }
}

// 지오펜싱: 이탈
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
    DispatchQueue.main.async {
        self.didEnterGeofence = false
        self.didExitGeofence = true
    }
}
  • 사용자가 지오펜스 영역에 들어오면(didEnterRegion)  didEnterGeofence = true
  • 사용자가 지오펜스 영역을 벗어나면(didExitRegion)  didExitGeofence = true
  • SwiftUI 화면이나 다른 로직에서 이 값을 읽어서 특정 행동(알림, 화면 전환 등)을 할 수 있

 


 

지오코딩 vs 역지오코딩

 

지오코딩

:  주소 → 위도 / 경도 좌표로 변환하는 과정

사용자가 “서울특별시 관악구 흑석로 84”라는 텍스트를 입력했을 때

이걸 지도에 표시하려면 해당 주소가 정확히 어떤 지점인지 좌표로 바꿔야 합니다.

즉, 사람이 읽을 수 있는 주소를 지도가 이해할 수 있는 좌표로 바꾸는 과정을 말합니다.

역지오코딩

: 위도 / 경도 좌표 → 주소 정보로 변환하는 과정

사용자가 지도에서 아무 곳이나 꾹 눌렀을 때

그 위치에 해당하는 주소가 무엇인지 보여줘야 할 수 있습니다.

 

 

MLLocalSearch

: 사용자가 입력한 키워드에 해당하는 장소를 지도에서 검색하고 결과를 가져오는 도구

// MKLocalSearch.Request :어떤 키워드로, 어떤 위치 기준으로 검색할지 설정
let request = MKLocalSearch.Request()
request.naturalLanguageQuery = "카페"
request.region = MKCoordinateRegion(...)

// MKLocalSearch : 실제로 검색을 실행하는 객체
let search = MKLocalSearch(request: request) 

// .start() : 비동기로 검색을 실행, 결과를 클로저로 변환
search.start { response, error in
    if let mapItems = response?.mapItems {
        // mapItems: [MKMapItem]
        // 각 장소의 위치, 이름, 주소 등 포함
    }
}


 

음 방향 전환 음음