I am new to Swift so this may be a problem due to my inexperience. I am trying to bind a MKCoordinateRegion variable in the MapView struct so that the map is automatically centered on the user, but setRegion() doesn't seem to be working even though region is getting correctly assigned to the user's location (I have made sure of this by placing print statements in the updateUIView function). Basically, the setRegion() function in updateUIView currently does nothing to change the default region. When I open up the simulation, the map stays located at the default starting location even after allowing the device to share location. I have tried setting the region to a random hardcoded location in the updateUIView function instead and this works fine, but something about trying to set it to the bound region variable doesn't seem to have any affect. What am I missing?
MapView struct:
struct MapView: UIViewRepresentable {
typealias UIViewType = MKMapView
@Binding var region: MKCoordinateRegion
let mapView = MKMapView()
func makeUIView(context: Context) -> MKMapView {
mapView.setRegion(region, animated: true)
mapView.showsUserLocation = true
return mapView
}
func updateUIView(_ uiView: MKMapView, context: Context) {
mapView.setRegion(region, animated: true)
}
}
ContentView:
struct ContentView: View {
@StateObject private var viewModel = ContentViewModel()
var body: some View {
VStack {
Text("Adventure Program")
.font(.largeTitle)
.multilineTextAlignment(.center)
MapView(region: $viewModel.region)
.onAppear {
viewModel.checkIfLocationServicesIsEnabled()
}
}.background(
Image("background")
.resizable()
.edgesIgnoringSafeArea(.all)
.scaledToFill())
}
}
ContentViewModel:
import MapKit
import SwiftUI
enum MapDetails {
static let startingLocation = CLLocationCoordinate2D(
latitude: 40.7,
longitude: -74)
static let defaultSpan = MKCoordinateSpan(
latitudeDelta: 1,
longitudeDelta: 1)
static let defaultRadius = 4000.0
}
final class ContentViewModel: NSObject, ObservableObject, CLLocationManagerDelegate {
var locationManager: CLLocationManager?
@Published var region = MKCoordinateRegion(
center: MapDetails.startingLocation,
span: MapDetails.defaultSpan)
func checkIfLocationServicesIsEnabled() {
if CLLocationManager.locationServicesEnabled() {
locationManager = CLLocationManager()
locationManager!.delegate = self
} else {
print("Show alert about this being off!")
}
}
private func checkLocationAuthorization() {
guard let locationManager = locationManager else { return }
switch locationManager.authorizationStatus {
case .notDetermined:
locationManager.requestWhenInUseAuthorization()
case .restricted:
print("Your location is restricted")
case .denied:
print("You have denied this app's location permission. Go into settings to change it.")
case .authorizedAlways, .authorizedWhenInUse:
region = MKCoordinateRegion(
center: locationManager.location!.coordinate,
span: MapDetails.defaultSpan)
@unknown default:
break
}
}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
checkLocationAuthorization()
}
}
CodePudding user response:
Hi Messenger_ welcome to stack overflow!
After doing some debugging, I found the solution, using DispatchQueue solved it for me.
Therefore, I added this into the MapView
struct like this:
struct MapView: UIViewRepresentable {
typealias UIViewType = MKMapView
@Binding var region: MKCoordinateRegion
var locationManager = CLLocationManager()
func makeUIView(context: Context) -> MKMapView {
let mapView = MKMapView()
mapView.showsUserLocation = true
return mapView
}
func updateUIView(_ view: MKMapView, context: Context) {
DispatchQueue.main.async {
mapView.setRegion(region, animated: false)
}
}
}
Hope this helps!