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)
}
}