I'm new to Swift development so if I've done something especially stupid, please let me know and I'll just delete the question.
I have a view that contains a map. On tap, I want to show an alert with the option to confirm a particular action.
As-is, attempting to show the alert results in:
Attempt to present X on Y whose view is not in the window hierarchy!
This is a work in progress and is nowhere near complete. Here is my current code:
import SwiftUI
import MapKit
import UIKit
import GoogleMaps
import GooglePlaces
import CoreLocation
final class MapsView: UIViewController, UIViewRepresentable, ObservableObject, GMSMapViewDelegate {
@Published var visible = false
@Published var coordinates:CLLocationCoordinate2D? = nil
let marker : GMSMarker = GMSMarker()
let locationManager = CLLocationManager()
var address = ""
init() {
// Get location permission.
locationManager.requestAlwaysAuthorization()
// Start getting location information.
if( CLLocationManager.authorizationStatus() == .authorizedWhenInUse ||
CLLocationManager.authorizationStatus() == .authorizedAlways){
// Start monitoring location.
locationManager.startUpdatingLocation()
}else{
// Don't show the view if we don't have permission.
// TODO: Its probably a good idea to give some feedback here.
visible = false
}
super.init(nibName:nil, bundle:nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
// Drop a marker where the user tapped.
// Confirm checkin.
// Remove existing markers.
mapView.clear()
coordinates = coordinate
showConfirm()
}
/// Creates a `UIView` instance to be presented.
func makeUIView(context: MapsView.Context) -> GMSMapView {
// Get lat/lon
let location = locationManager.location
let coords = location?.coordinate
let lat = coords?.latitude
let lon = coords?.longitude
// Set camera position.
let camera = GMSCameraPosition.camera(withLatitude: lat!, longitude: lon!, zoom: 17.0)
let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
// Enable "my location"
mapView.isMyLocationEnabled = true
// Set the delegate.
mapView.delegate = self
return mapView
}
func updateUIView(_ mapView: GMSMapView, context: MapsView.Context) {
// TODO
}
func showConfirm() {
if coordinates != nil {
// Get the address.
let gc = GMSGeocoder()
gc.reverseGeocodeCoordinate(coordinates!) { (response, error) in
// Get the first address result.
let result = response?.firstResult()
// Build the address string.
self.address = ""
for line in (result?.lines)! {
self.address += " " + line
}
// Create an alert.
let alert = UIAlertController(title: "Confirm Checkin", message: "Check in to \(self.address)?", preferredStyle: UIAlertController.Style.alert)
// Add NO button.
alert.addAction(UIAlertAction(title: "NO", style: UIAlertAction.Style.cancel, handler: nil))
// Add YES button.
alert.addAction(UIAlertAction(title: "YES", style: UIAlertAction.Style.default))
// Show the alert.
self.present(alert, animated: true, completion: nil)
}
}
}
}
From the following, how can I show an Alert without this error?
// Create an alert.
let alert = UIAlertController(title: "Confirm Checkin", message: "Check in to \(self.address)?", preferredStyle: UIAlertController.Style.alert)
// Add NO button.
alert.addAction(UIAlertAction(title: "NO", style: UIAlertAction.Style.cancel, handler: nil))
// Add YES button.
alert.addAction(UIAlertAction(title: "YES", style: UIAlertAction.Style.default, handler: nil))
// This line produces the error
self.present(alert, animated: true, completion: nil)
I'm aware of this question, but I don't have a viewDidAppear
method and I'm not sure how to properly move my logic into one, as I want this alert displayed when the map is touched, rather than when the view appears.