import SwiftUI
import MapKit
import CoreLocation
struct Location: Identifiable {
let id = UUID()
let name: String
let coordinate: CLLocationCoordinate2D
}
struct MapView: View {
@StateObject private var locationManager = LocationManager()
@State private var region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194),
span: MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)
)
let locations = [
Location(name: "San Francisco", coordinate: CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194)),
Location(name: "Los Angeles", coordinate: CLLocationCoordinate2D(latitude: 34.0522, longitude: -118.2437)),
Location(name: "San Diego", coordinate: CLLocationCoordinate2D(latitude: 32.7157, longitude: -117.1611))
]
var body: some View {
ZStack(alignment: .bottomTrailing) {
Map(coordinateRegion: $region, showsUserLocation: true, annotationItems: locations) { location in
MapAnnotation(coordinate: location.coordinate) {
VStack {
Image(systemName: "mappin.circle.fill")
.foregroundColor(.red)
.font(.title)
Text(location.name)
.font(.caption)
.padding(4)
.background(Color.white)
.cornerRadius(4)
}
}
}
VStack(spacing: 10) {
Button {
if let userLocation = locationManager.location {
region.center = userLocation
}
} label: {
Image(systemName: "location.fill")
.padding()
.background(Color.white)
.clipShape(Circle())
.shadow(radius: 3)
}
}
.padding()
}
.onAppear {
locationManager.requestPermission()
}
}
}
class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
private let manager = CLLocationManager()
@Published var location: CLLocationCoordinate2D?
@Published var authorizationStatus: CLAuthorizationStatus?
override init() {
super.init()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
}
func requestPermission() {
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
location = locations.first?.coordinate
}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
authorizationStatus = manager.authorizationStatus
}
func geocodeAddress(_ address: String, completion: @escaping (CLLocationCoordinate2D?) -> Void) {
let geocoder = CLGeocoder()
geocoder.geocodeAddressString(address) { placemarks, error in
completion(placemarks?.first?.location?.coordinate)
}
}
func reverseGeocode(coordinate: CLLocationCoordinate2D, completion: @escaping (String?) -> Void) {
let geocoder = CLGeocoder()
let location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
geocoder.reverseGeocodeLocation(location) { placemarks, error in
if let placemark = placemarks?.first {
let address = [
placemark.thoroughfare,
placemark.locality,
placemark.administrativeArea,
placemark.postalCode
].compactMap { $0 }.joined(separator: ", ")
completion(address)
} else {
completion(nil)
}
}
}
}
MapKit displays interactive maps with annotations, overlays, and user location. SwiftUI's Map view simplifies basic map integration with declarative syntax. I add annotations for points of interest, polylines for routes, and polygons for regions. MKCoordinateRegion sets the visible map area. Location updates require CLLocationManager with proper permission requests. For custom annotations, I use MKAnnotationView with UIKit or MapAnnotation in SwiftUI. Geocoding converts addresses to coordinates with CLGeocoder. Reverse geocoding does the opposite. For directions, MKDirections calculates routes between locations. MapKit also supports clustering annotations, displaying traffic, and satellite imagery.