0

I have been stuck on this problem for the last three weeks and can't seem to get past it, it's driving me insane. I believe that I have all the correct code, but it is just not ordered properly. I am currently designing an app somewhat like Uber, but a completely different concept.

What I am trying to do is pull down coordinates from Firebase and then drop two "pins" or markers on a GMSMapview. I have a UIView classed as GMSMapview and wired up via an IBOutlet. So when the ViewController loads the Google Maps MapView is in the UIView. What I am trying to accomplish is having a "pin" where the current "driver" is and a second pin where "my" location is. What I want to accomplish is for the map to "zoom & follow" the driver until he arrives at my location, similar to Uber.

I have tried hundreds of different types of code combinations and found articles here on StackOverflow that I followed, but those did not work. I was able to get the pins to show up (green is driver, red is where he is going) and when I went into Firebase and changed one of the coordinates the screen would "jump" or flicker really bad. Doing some more research I read that in order to accomplish this concept (and to show all the "cars" as markers on a GMS MapView as Uber does, in another ViewController) I need to put my coordinates in an array, and then loop through a model containing a struct with the variables. Once I did that, the "flickering" stopped, but then the whole view controller continued to reload from scratch(as if the ViewController was just opened for the first time) every time I updated a coordinate. Sometimes I did latitude and other times longitude, but it made no difference. Obviously since I was updating Firebase manually, i could not do both values at the same time.

The articles I found on StackOverflow seemed very promising and I believe I am on the right track, except after implementing some of the recommended code from Google and here, I am now getting a nil crash (identified in my code below). This crash is occurring after I go into Firebase and manually update a coordinate (either lat or long).

After almost a month of trying to tweak and get this code to work, I am looking for some guidance as to where I have gone wrong with my code. I am using the latest PODS for GoogleMaps and Firebase. Bottom line, I am looking for the way to move the GMS Marker while the coordinates update live in Firebase, as well as have the map zoom in as it gets closer to "my location".

Here are the articles I researched and followed: GMS Map View Maker Flicker issue

How do I move marker along with moving of Google Map in iOS?

Here is my code:

import UIKit
import CoreLocation
import CoreData
import Firebase
import FirebaseDatabase
import FirebaseAuth
import GoogleMaps
import GooglePlaces
import GooglePlacesPicker
import Alamofire
import SwiftyJSON

class SOPOST: UIViewController, CLLocationManagerDelegate, GMSMapViewDelegate, Alertable {

    @IBOutlet weak var connectedMapView: GMSMapView!
    @IBOutlet weak var driverInfoView: UIView!

    let currentUserId = Auth.auth().currentUser?.uid

    var markers = [] as NSArray

    var locationManager = CLLocationManager()
    var placesClient: GMSPlacesClient!
    var zoomLevel: Float = 12.0
    var likelyPlaces: [GMSPlace] = []
    var selectedPlace: GMSPlace?

    var custlat: CLLocationDegrees?
    var custlong: CLLocationDegrees?
    var driverlat: CLLocationDegrees?
    var driverlong: CLLocationDegrees?
    var destlat: CLLocationDegrees?
    var destlong: CLLocationDegrees?

    var location: CLLocation?

    var destinationMarker = GMSMarker()


    var currentCoordAddress: CLLocationCoordinate2D?
    var destinationCoordAddress: CLLocationCoordinate2D?
    var driverCoordAddress: CLLocationCoordinate2D?


    override func viewDidLoad() {
        super.viewDidLoad()

        connectedMapView.delegate = self
        DispatchQueue.main.async {
            DataService.instance.REF_TRIPS.observe(.value, with: { (snapshot) in
                if let findDriverSnapshot = snapshot.children.allObjects as? [DataSnapshot] {
                    for driver in findDriverSnapshot {
                        if driver.childSnapshot(forPath: "passengerKey").value as? String == self.currentUserId! {
                            let acceptanceStatus = driver.childSnapshot(forPath: "tripIsAccepted").value as! Bool
                            if acceptanceStatus == true {
                                if let observeAcceptDict = driver.value as? Dictionary<String, AnyObject> {
                                    let pickupCoordinateArray = observeAcceptDict["pickupCoordinate"] as! NSArray
                                    self.custlat = pickupCoordinateArray[0] as? CLLocationDegrees
                                    self.custlong = pickupCoordinateArray[1] as? CLLocationDegrees

                                    let driverCoordinateArray = observeAcceptDict["driverCoordinate"] as! NSArray
                                    self.markers = observeAcceptDict["driverCoordinate"] as! NSArray
                                    self.driverlat = driverCoordinateArray[0] as? CLLocationDegrees
                                    self.driverlong = driverCoordinateArray[1] as? CLLocationDegrees
                                    let prepareLocation = CLLocation(latitude: self.driverlat!, longitude: self.driverlong!)
                                    self.location = prepareLocation
                                    let destCoordinateArray = observeAcceptDict["destinationCoordinate"] as! NSArray
                                    self.destlat = destCoordinateArray[0] as? CLLocationDegrees
                                    self.destlong = destCoordinateArray[1] as? CLLocationDegrees
                                    self.currentCoordAddress = CLLocationCoordinate2DMake(self.custlat!, self.custlong!)
                                    self.destinationCoordAddress = CLLocationCoordinate2DMake(self.destlat!, self.destlong!)
                                    self.driverCoordAddress = CLLocationCoordinate2DMake(self.driverlat!, self.driverlong!)
                                    CATransaction.begin()
                                    CATransaction.setAnimationDuration(1.0)
                                    self.destinationMarker.position = CLLocationCoordinate2D(latitude: (self.markers[0] as? CLLocationDegrees)!, longitude: (self.markers[1] as? CLLocationDegrees)!)
                                    self.connectedMapView.camera = GMSCameraPosition.camera(withTarget: self.destinationMarker.position, zoom: 12.0)

                                    self.destinationMarker.icon = GMSMarker.markerImage(with: UIColor.green)
                                    self.destinationMarker.map = self.connectedMapView
                                    self.destinationMarker.tracksViewChanges = false
                                    CATransaction.commit()

                                    let customerdestmarker = GMSMarker()
                                    customerdestmarker.position = CLLocationCoordinate2D(latitude: self.custlat!, longitude: self.custlong!)
                                    customerdestmarker.icon = GMSMarker.markerImage(with: UIColor.red)
                                    customerdestmarker.map = self.connectedMapView
                                    customerdestmarker.tracksViewChanges = false

                                }
                            }
                        }
                    }
                }
            })

        }

    }

    func updateLocationoordinates(coordinates:CLLocationCoordinate2D) {
        if destinationMarker == nil
        {
            destinationMarker = GMSMarker()
            destinationMarker.position = coordinates
            let image = UIImage(named:"destinationmarker")
            destinationMarker.icon = image
            destinationMarker.map =  self.connectedMapView
            destinationMarker.appearAnimation = GMSMarkerAnimation.pop
        }
        else
        {
            CATransaction.begin()
            CATransaction.setAnimationDuration(1.0)
            destinationMarker.position =  coordinates
            CATransaction.commit()
        }
    }

    func mapView(_ mapView: GMSMapView, didChange position: GMSCameraPosition) {
        self.destinationMarker = GMSMarker(position: self.location!.coordinate)  // <----CRASHES HERE: Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
        destinationMarker.position = position.target
        let destinationLocation = CLLocation(latitude: destinationMarker.position.latitude, longitude: destinationMarker.position.longitude)
        let destinationCoordinate = destinationLocation.coordinate
        updateLocationoordinates(coordinates: destinationCoordinate)
    }

}
MrUpsidown
  • 21,592
  • 15
  • 77
  • 131
Greg
  • 67
  • 7
  • @Geg Crash happens because mapView(_ mapView: GMSMapView, didChange position: GMSCameraPosition) method called and still location with nil, so you should check if location is not nil before using it. – Hosny Feb 11 '19 at 08:35
  • @Hosny. Didn’t I already do that? When viewDidLoad is run the there is the observer reading from FB and putting it into variables and then the func mapView is reading those variables and should update when new coordinates are there. – Greg Feb 11 '19 at 12:28
  • Yes, but FB take time to get data and assigned it to location variable, and map method called immediately so crash happens. – Hosny Feb 11 '19 at 13:27

0 Answers0