App crashes when run more than once on GMSMAPVIEW - ios

I have an app that finds places near the user’s location, however, the app crashes the second time it runs with the exception:
fatal error: unexpectedly found nil while unwrapping an Optional value.
On line:
self.googleMapView.animate(toLocation: coordinates)
I checked and the googleMapView is nil but I don’t understand how it is nil or how it ran the first time. It only starts crashing on subsequent tries if I delete and reinstall the app it works fine on the first try but after that it keeps crashing even if I restart the app. Full code below
import UIKit
import GoogleMaps
import GooglePlacePicker
import MapKit
class MapViewController: UIViewController, CLLocationManagerDelegate {
var currentLongitude: CLLocationDegrees = 0
var currentLatitude: CLLocationDegrees = 0
var locationManager: CLLocationManager!
var placePicker: GMSPlacePickerViewController!
var googleMapView: GMSMapView!
#IBOutlet weak var mapViewContainer: MKMapView!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.googleMapView = GMSMapView(frame: self.mapViewContainer.frame)
self.googleMapView.animate(toZoom: 18.0)
self.view.addSubview(googleMapView)
}
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager = CLLocationManager()
self.locationManager.delegate = self
self.locationManager.requestAlwaysAuthorization()
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location:CLLocation = locations.last {
self.currentLatitude = location.coordinate.latitude
self.currentLongitude = location.coordinate.longitude
}
else {
print("Location Error")
}
let coordinates = CLLocationCoordinate2DMake(self.currentLatitude, self.currentLongitude)
let marker = GMSMarker(position: coordinates)
marker.title = "I am here"
marker.map = self.googleMapView
self.googleMapView.animate(toLocation: coordinates)
}
private func locationManager(manager: CLLocationManager,
didFailWithError error: Error){
print("An error occurred while tracking location changes : \(error.localizedDescription)")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

Crash is pretty self-explanatory:
You are setting your location's delegate in the viewDidLoad but creating the map in the viewDidAppear.
If the location was known by iOS, you will receive the message before viewDidAppear call so in the line : self.googleMapView.animate(toLocation: coordinates), your map is still nil
You can either define your map as optional : var googleMapView: GMSMapView?, or you can wait for your map to be defined to create your location Manager.

Related

MKMapView seems to be nil?

I am new to Xcode and Swift and I am trying to simply make a map that shows the users current location and updates it. I have this so far:
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var map: MKMapView!
let locationManager = CLLocationManager()
var mapp = MKMapView.self
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
if (CLLocationManager.locationServicesEnabled())
{
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
self.map.showsUserLocation = true
}
else
{
print("Location services are not enabled")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func loadView() {
//let camera = GMSCameraPosition.camera(withLatitude: 36.2108, longitude: -81.6774, zoom: 15.0)
//let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
//mapView.isMyLocationEnabled = true
//view = mapView
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
let location = locations.last
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.002, longitudeDelta: 0.002))
self.map.setRegion(region, animated: true)
self.locationManager.stopUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error)
{
print("Errors: " + error.localizedDescription)
}
}
I have made a MapView in the storyboard and CTRL dragged it to the file (thus the #IBOutlet weak var map: MKMapView!). However, when I plug my phone in and simulate the app it gives me a "unexpectedly found nil while unwrapping an optional value" and after some print statements i found that it happened whenever I referenced the map variable. Why is this? Thanks!
In the comments of the original post, Rob answered the question:
"
Remove the loadView method. That's used only when you are programmatically creating views. When using storyboards (or NIBs), you put your configuration code in viewDidLoad, not loadView. – Rob"
thank you Rob

'MKMapView' / 'showsUserLocation = true' causing error with modal segue

I am developing a small map application which allows users to view their current location. I have the relevant code to perform this and it seems to work as expected:
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate, UISearchBarDelegate, UIPopoverPresentationControllerDelegate {
// CLlocation
var location: CLLocation!
let locationManager = CLLocationManager()
// Map variables
var searchController:UISearchController!
var annotation:MKAnnotation!
var localSearchRequest:MKLocalSearchRequest!
var localSearch:MKLocalSearch!
var localSearchResponse:MKLocalSearchResponse!
var error:NSError!
var pointAnnotation:MKPointAnnotation!
var pinAnnotationView:MKPinAnnotationView!
// IBOutlets
#IBOutlet weak var placesMap: MKMapView!
// Location function
func locationManager(manager: CLLocationManager, didUpdateqLocations locations: [CLLocation]) {
let location = locations.last
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
self.placesMap.setRegion(region, animated: true)
self.locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError)
{
print("Error code: " + error.localizedDescription)
}
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
self.placesMap.showsUserLocation = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
However, when I launch a modal segue to the 'About' page, from a popover (pictured below), the app crashes:
I viewed the error given to me in the terminal, this was
fatal error: unexpectedly found nil while unwrapping an Optional value
Xcode pointed me to this particular line in my viewDidLoad function:
self.placesMap.showsUserLocation = true
When I delete that particular line from my code, the location feature no longer functions, this is obvious. I have checked the outlet to the MKMapView and it seems to be correct.
I really don't know how to avoid this error, or for certainty what is causing it, so any help is appreciated.
Basically, something is making the placesMap deallocate and then viewDidLoad is being called. You might try making the placesMap optional instead of force unwrapping it, so change the ! to a ? on the property and then chain the optional into the call sites of placesMap, so self.placesMap.showsUserLocation becomes self.placesMap?.showsUserLocation and self.placesMap.setRegion(region, animated: true) becomes self.placesMap?.setRegion(region, animated: true)

ios SWIFT found nil while unwrapping option value.

After doing some research and asking other question on stack i can not seem to figure out the issue. Yet i have come far.
I am new to Stack so please let me know if i need to provide more information.
The error is appering at
self.mapView.showsUserLocation = true
Saying in the compiler
fatal error: unexpectedly found nil while unwrapping an Option Value
IIDB
if i delete that line the error appears on a another .mapView. line.
When i move the line where the error appear, and put it under:
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
The app opens and everything works fine, except it dont show the location, but i am able to run the app without getting any error.
Thank you for your time.
Here is my codes if someone need it.
import UIKit
import Parse
import CoreLocation
import MapKit
class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
self.mapView.showsUserLocation = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Location Delegate Methods
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 1, longitudeDelta: 1))
self.mapView.setRegion(region, animated: true)
self.locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("Error:" + error.localizedDescription)
}
}
The only reason why it would be returning a found nil error on a property would be because the property had not yet been instantiated. Given that you're using an IBOutlet, I imagine that you haven't hooked the property to the map view in your storyboard.
See Swift: "mapView.showUserLocation = true" returns "fatal error: unexpectedly found nil while unwrapping an Optional value (lldb) " for more info.
Try to add locationManager.requestLocation() instead of self.mapView.showsUserLocation = true
Check if your info.plist contains 'Privacy - Location Usage Description'

SWIFT Thread 1: EXC Bad instruction XCODE IOS

I am very new to stackexchange so please let me know if i need to provide more information.
I tried to install the Corelocation and Mapkit and use them togheter. Every since i followed Vea Software Tutorial i have recived the following error:
Thread 1: EXC_BAD_INSTRUCTION(code=EXC_1386_INVOP,subcode=0x0)
In the compiler it says
fatal error: Unexpectedly found nil while unwrapping an Optional
Value(llDB)
The error is appering right at this line, but when i delete it, it appears at another Mapkit/Location core line. The error:
self.mapView.showsUserLocation = true
EDIT: When i remove the line above, the same error appears on
self.mapView.setRegion(region, animated: true)
I have been searching around for a while on the internet but nothing really helps me out. Thank you for your time.
If you need the whole viewcontroller code. Here it is.
import UIKit
import Parse
import CoreLocation
import MapKit
class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
let locationManager = CLLocationManager()
#IBOutlet var UsernameTextField: UITextField!
#IBOutlet var PasswordTF: UITextField!
#IBOutlet var EmailTF: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
self.mapView.showsUserLocation = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Location Delegate Methods
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 1, longitudeDelta: 1))
self.mapView.setRegion(region, animated: true)
self.locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("Error:" + error.localizedDescription)
}
}
This just an hypothesis by I noticed you use
self.mapView.setRegion(region, animated: true)
in the CLLocationManager delegate and start updating before mapView is actually showing (i.e. in viewDidLoad).
Could it be that mapView is trying to update its visual states before being installed in the view hierarchy ?

location constantly updating problems iOS Swift

I am getting the users current location and dropping this as a println(). The idea is that I am going to hit a button to get the new location, however currently the app keeps updating constantly (every second) instead. I have tried moving the getLocation() function inside my IBAction but that crashed the thing. I have updated the info.plist so thats not a problem. Heres le code:
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate{
#IBOutlet var latitude : UILabel!
#IBOutlet var longitude : UILabel!
var locationManager = CLLocationManager()
var startLocation: CLLocation!
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func findMyLocation(sender: AnyObject){
startLocation = nil
locationManager.startUpdatingLocation()
}
func getLocation(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!){
var userLocation:AnyObject = locations[0] as! CLLocation
var strlat = String(format: "%.4f", userLocation.coordinate.latitude)
var strlong = String(format: "%.4f",userLocation.coordinate.longitude)
latitude.text = String(format: "%.4f", userLocation.coordinate.latitude)
longitude.text = String(format: "%.4f",userLocation.coordinate.longitude)
println("latitude: " + strlat)
println("longitide: " + strlong)
if startLocation == nil {
startLocation = userLocation as! CLLocation
locationManager.stopUpdatingLocation()
}
}
func locationManager(manager: CLLocationManager!,
didFailWithError error: NSError!) {
}
}
Move the locationManager.startUpdatingLocation() to your findMyLocation function. This will start the locationManager when your button is pressed and begin calling the didUpdateLocations Inside your if startLocation == nil add locationManager.stopUpdatingLocation() this will stop the locationManager after you have set your startLocation var. Every time the user presses the button the process will run again.
One additional note, you should add more code into the didUpdateLocations to check the accuracy and timestamp of the location before you use it as it may not be a valid/accurate location for what you are trying to do.
UPDATE:
Had a chance to validate and the code will work with the changes suggested. Here is what your final code should look like. I am also assuming you have set your plist entries for locations services and your simulator is set to simulate locaitons.
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate{
#IBOutlet var latitude : UILabel!
#IBOutlet var longitude : UILabel!
var locationManager : CLLocationManager! = CLLocationManager()
var startLocation: CLLocation!
override func viewDidLoad() {
super.viewDidLoad()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func findMyLocation(sender: AnyObject){
startLocation = nil
locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!){
var userLocation:AnyObject = locations[0] as! CLLocation
var strlat = String(format: "%.4f", userLocation.coordinate.latitude)
var strlong = String(format: "%.4f",userLocation.coordinate.longitude)
latitude.text = String(format: "%.4f", userLocation.coordinate.latitude)
longitude.text = String(format: "%.4f",userLocation.coordinate.longitude)
println("latitude: " + strlat)
println("longitide: " + strlong)
if startLocation == nil {
startLocation = userLocation as! CLLocation
locationManager.stopUpdatingLocation()
}
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
println("error with location manager: " + error.description)
}
}

Resources