TIL: MapKit (1) 2025.07.03

박춘팔·4일 전
0

Swift TIL

목록 보기
9/9
post-thumbnail

생각보다 정말 많이 사용하게되는 GPS와 지도 기능을 사용해보고 싶어졌다.

Swift가 생각보다 양질의 자료가 많지 않아서 모호했는데 잘 정리해보려고 한다.

나처럼 프론트엔드를 경험하고 Swift를 하는 사람들은 지도를 띄운다하면 재사용을 고려해서 분명 분리하려고 할 것이다.

그래서 루트에 MapView.swift를 만들어서 분리해줬다.

디렉토리 구조는 다음에 글을 제대로 작성해보겠다(나도 궁금해서 빨리 알아보고 싶어졌다.)

MapKit

import SwiftUI
import MapKit

struct MapView: UIViewRepresentable {
    @Binding var region: MKCoordinateRegion
    
    func makeUIView(context: Context) -> MKMapView {
        let mapView = MKMapView()
        
        mapView.delegate = context.coordinator
        return mapView
    }
    
    func updateUIView(_ uiView: MKMapView, context: Context) {
        uiView.setRegion(region, animated: true)
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, MKMapViewDelegate {
        var parent: MapView
        
        init(_ parent: MapView) {
            self.parent = parent
        }
    }
    
}

일단 전체코드는 이렇다.

구분 분석을 하나하나 해보겠다.

// SwiftUI 프레임워크를 사용하기 위해 필요
// SwiftUI를 기반으로하는 컴포넌트 뷰 임을 명시
import SwiftUI

// Apple의 지도API인 MapKit을 가져온다.
// MKMapView, MKCoordinateRegion, CLLocationCoordinate2D 등 MapKit 타입 사용가능
import MapKit 


// MapView는 SwiftUI 뷰
// UIKit의 뷰를 SwiftUI에서 사용하기 위한 래퍼

struct MapView: UIViewRepresentable {

UIVIewRepresentable 이란?
UIKit의 뷰를 SwiftUI에서 사용할 수 있도록 브릿지 역할을 해주는 프로토콜

MKMapView, UITextField, UIView Animation, UICollectionView 등 UIKit 기반의 강력한 컴포넌트를 SwiftUI에서 그대로 사용할 수 없기 때문에 UIViewRepresentable을 사용해 UIKit 뷰를 감쌀 수 있는 인터페이스를 제공

UIVIewRepresentable 프로토콜을 사용하려면 두가지 필수 메서드를 구현해야함

func makeUIView(context: Context) -> UIViewType
func updateUIView(_ UIViewType, context: Context)

이어서 코드를 살펴보면

// @Binding -> 외부 뷰에서 전달된 상태값을 양방향으로 공유할 수 있게 해줌
// 외부 @State 변수와 연결
@Binding var region: MKCoordinateRegion

// UIViewRepresentalbe 필수 메서드
// SwiftUI가 처음으로 UIKit 뷰 생성시 호출
func makeUIView(context: Context) -> MKMapView {
	let mapView = MKMapView()
    mapView.delegate = context.coordinator
  	
  	return mapView
}

delegate 란?
delegate는 UIKit 컴포넌트가 자신의 동작을 외부에 알려주는 방식, UIKit에서는 이벤트 처리 시 자주 사용

// 마찬가지로 필수 메서드
// region값이 변경되면 해당 메서드 호출, UIKit 뷰의 상태 업데이트
// MKMapView의 현재 지도를 외부에서 바인딩 된 값으로 갱신
func updateUIView(_ uiView: MKMapView, context: Context) {
	uiView.setRegion(region, animated: true)
}

// SwiftUI에서 사용될 context.coordinator 에 사용되는 객체 반환
// delegate 작업에 사용될 중간 객체 생성
func makeCoordinator() -> Coordinator {
	Coordinator(self)
}

// MKMapViewDelegate를 채택한 클래스 -> MKMapView의 이벤트 처리용 delegate
// regionDidChange, annotaionView, overlayRenderer등 다양한 메서드 오버라이드 가능
// parant는 MapView 뷰 인스턴스 참조
class Coordinator: NSObject, MKMapViewDelegate {
	var parent: MapView
    
    init(_ parant: MapView) {
    	self.parent = parent
    }
}

전체적 흐름은
1. SwiftUI에서 MapView(region: $someRegion) 처럼 사용
2. 내부에서 makeUIView() 를 통해 MKMapView 생성
3. SwiftUI 상태(region)가 바뀌면 updateUIView()에서 지도 업데이트
4. 지도 상에서 사용자 인터렉션 발생 시 Coordinator 통해 이벤트 처리

profile
이것 저것 다해보는 삶

0개의 댓글