Building Name using current location - swift

I am trying to get House number using CLLocationManagerDelegate and MKMapViewDelegate but it did not work. By using this i am getting Sub-locality area and sub administrative thoroughfare and sub-through fare but not getting building name.
Please help how to get building name
I have already tried using CLLocationManagerDelegate method reversegeocoder and CLLocationManagerDelegate.
CLGeocoder().reverseGeocodeLocation(location){ (placemark, error) in
let place = placemark?[0]
print(placemark?[0].addressDictionary?[0])
let subloc = place?.subLocality
let city = place?.locality
print("\(subloc!),\(city!),\(place?.administrativeArea)")
print(place?.areasOfInterest?.count)
if let subLocal = place?.subLocality, let cityCustom = place?.locality
{
self.locationname.text = ("\(subLocal),\(cityCustom)")
self.locationname.text = (placemark?[0].addressDictionary?[0]) as? String
self.address = self.locationname.text ?? ""
print(placemark?[0].addressDictionary?[0]) as? String
if let marks = placemark, marks.count > 0 {
let placemark = marks[0]
let postalAddress = placemark.addressDictionary
if let address = postalAddress?.first {
print("\(address)")
}
if let State = placemark.addressDictionary?["State"]{
print("\(State)")
}
if let Street = placemark.addressDictionary?["Street"]{
print("\(Street)")
}
if let Name = placemark.addressDictionary?["Name"]{
print("\(Name)")
}
if let Thoroughfare = placemark.addressDictionary?["Thoroughfare"]{
print("\(Thoroughfare)")
}
if let subThoroughfare = placemark.addressDictionary?["SubThoroughfare"]{
print("\(subThoroughfare)")
}
if let FormattedAddressLines = placemark.addressDictionary?["FormattedAddressLines"]{
print("\(FormattedAddressLines)")
self.locationname.text = (FormattedAddressLines as AnyObject).componentsJoined(by: ",") as? String
self.address = self.locationname.text ?? ""
self.locationname.numberOfLines = 2
self.locationname.sizeToFit()
self.locationname.textAlignment = .center
}
}
}
else
{
self.alertbox(title1: UrlSheet.UrlName.msgTitle, message1: "Location service is disabled on your phone at the moment. Please enable the same before marking the attendance.")
}
self.mapviews.isUserInteractionEnabled = false
manager.stopUpdatingLocation()
}
Expected Result:
DLf-Tower A, Jasola Distric Center,New Delhi
Actual Result: Jasola Distric Center,New Delhi

Visit: https://developer.apple.com/documentation/corelocation/clplacemark For All Supported Placemark by Apple

Related

Eureka Swift - set value of LocationRow

I've got a form where a user can pick from a number of objects that includes co-ordinate data, which I want to load into a LocationRow.
I have tried several different ways to try and set the Location Row value, but it either crashes (unexpectedly found nil while unwrapping an optional Value) or doesn't reload the table with the correct data. i.e. https://i.imgur.com/2XkeHbu.png
My LocationRow eureka code:
$0.rowRight = LocationRow(){
$0.title = "Location"
$0.tag = "location"
if let page = selectedPage {
if let pageLocationLatitude = page.locationLatitude.value,
let pageLocationLongutude = page.locationLongitude.value {
print("testing for row update")
$0.value = CLLocation(latitude: pageLocationLatitude, longitude: pageLocationLongutude)
}
}
}
and the function that is called when I want to update the LocationRow
private func setSelectedPage(pageName : String) {
print("setting location of page: \(pageName)")
if pageName == username {
return
}
selectedPage = userPages?.filter("name == \"\(pageName)\"").first
if let locationLongitude = selectedPage?.locationLongitude.value,
let locationLatitude = selectedPage?.locationLatitude.value {
print("lat and lon: \(locationLatitude) \(locationLongitude)")
/*PURELY FOR TESTING
let titleRow = self.form.rowBy(tag: "title") as! TextRow
titleRow.value = "TEST WORKS OK"
titleRow.updateCell()
PURELY FOR TESTING */
let locationRow = self.form.rowBy(tag: "location") as! LocationRow
locationRow.value = CLLocation(latitude: locationLatitude, longitude: locationLongitude)
self.form.rowBy(tag: "location")?.updateCell()
}
self.tableView.reloadData()
}
From your code, I can see that you are putting this location row in a SplitRow:
// rowRight is a property of SplitRow
$0.rowRight = LocationRow(){
Therefore, the form doesn't really know about the location row. It only knows about the split row. You should get the split row using its tag first, then access rowRight.
// use the tag of your split row here!
let splitRow = self.form.rowBy(tag: "splitRow")
as! SplitRow<SomeRow, LocationRow> // replace SomeRow with the type of row on the left of the split row
let locationRow = splitRow.rowRight
locationRow.value = CLLocation(latitude: locationLatitude, longitude: locationLongitude)
locationRow.updateCell()

Retrieve data from Firebase before adding to a map

I'm building an application where a user can store companies information (like name, address, latitude, longitude to a Firebase real-time database).
With that information, those companies are then presented in a map as annotations.
My viewDidLoad is shown below
override func viewDidLoad() {
super.viewDidLoad()
// Definitions
let autenticacao = Auth.auth()
let idUsuarioLogado = (autenticacao.currentUser?.uid)!
let database = Database.database().reference()
let usuarios = database.child("usuarios")
let clinicas = database.child("clinicas")
// Map - User location
self.mapa.delegate = self
self.gerenciadorLocalizacao.delegate = self
self.gerenciadorLocalizacao.desiredAccuracy = kCLLocationAccuracyBest
self.gerenciadorLocalizacao.requestWhenInUseAuthorization()
self.gerenciadorLocalizacao.startUpdatingLocation()
// retrieve user information
usuarios.child(idUsuarioLogado).observe(DataEventType.value) { (snapshot) in
let dados = snapshot.value as? NSDictionary
let emailUsuario = dados?["email"] as! String
let nomeUsuario = dados?["nome"] as! String
let perfilUsuario = dados?["perfil"] as! String
let idUsuario = snapshot.key
let usuario = Usuario(email: emailUsuario, nome: nomeUsuario, uid: idUsuario, perfil: perfilUsuario)
print("User profile \(perfilUsuario)")
}
// Clinicas listeners
clinicas.observe(DataEventType.childAdded) { (snapshot) in
let dados = snapshot.value as? NSDictionary
//print("Dados na leitura \(dados)")
let clinica = Clinica()
clinica.identificador = snapshot.key
clinica.nome = dados?["nome"] as! String
clinica.endereco = dados?["endereco"] as! String
clinica.cidade = dados?["cidade"] as! String
clinica.cep = dados?["cep"] as! String
clinica.estado = dados?["estado"] as! String
clinica.latitude = dados?["latitude"] as! String
clinica.longitude = dados?["longitude"] as! String
clinica.urlImagem = dados?["urlImagem"] as! String
clinica.idImagem = dados?["idImagem"] as! String
self.clinicasR.append(clinica)
}
// add annotations to the map
for oneObject in self.todasAnotacoes {
print("Oneobj \(oneObject)")
let umaAnotacao = MinhaAnotacao()
var oneObjLoc: CLLocationCoordinate2D = CLLocationCoordinate2DMake(oneObject.objLat, oneObject.objLong)
umaAnotacao.coordinate = oneObjLoc
umaAnotacao.title = oneObject.objName
umaAnotacao.subtitle = oneObject.objDesc
umaAnotacao.category = oneObject.objCat
self.anotacaoArray.append(umaAnotacao)
self.mapa.addAnnotations(self.anotacaoArray)
}
}
My viewDidLoad is "structured" in 4 main blocks (even though they run in a different order given they are asynchronous):
Definition;
Retrieve user profile;
Retrieve companies information (name, latitude, longitude);
Add annotations to the map.
As those are asynchronous functions, they run in different order and this is what is causing trouble to me.
note: There is still one piece missing here that is to feed all annotations to the variable todasAnotacoes which I'll do once I can retrieve data before triggering add annotation "block".
As annotation info comes from the firebase database, I should only have it executed once the clinicas.observe(DataEventType.childAdded) { (snapshot) in is concluded.
As is today, the sequence Xcode runs is:
Definitions
Add annotations;
retrieve data from firebase with companies details
I've tried adding the add annotation block to the closure, adding a dispatchqueue but none of those really worked. I also did a lot os search in stackoverflow but I couldn't find anything that i can use (or I wasn't able to understand).
So, in summary I need to run the add annotations after retrieving all data from Firebase.
Any ideas on how I could do that?
EDIT 1 - Final code with the suggested updates
override func viewDidLoad() {
super.viewDidLoad()
// Retrieving Logger user data and hidding "add" button if applicable
ProgressHUD.show("Carregando...")
let autenticacao = Auth.auth()
let idUsuarioLogado = (autenticacao.currentUser?.uid)!
let database = Database.database().reference()
let usuarios = database.child("usuarios")
var isUserLoaded = false
var isClinicsLoaded = false
usuarios.child(idUsuarioLogado).observe(DataEventType.value) { (snapshot) in
let dados = snapshot.value as? NSDictionary
let emailUsuario = dados?["email"] as! String
let nomeUsuario = dados?["nome"] as! String
let perfilUsuario = dados?["perfil"] as! String
let idUsuario = snapshot.key
let usuario = Usuario(email: emailUsuario, nome: nomeUsuario, uid: idUsuario, perfil: perfilUsuario)
isUserLoaded = true
if (isUserLoaded && isClinicsLoaded) {
self.addAnnotationsToMap();
}
//print("\(usuario.email) e \(usuario.nome) e \(usuario.uid) e \(usuario.perfil)")
}
// Option to code above
/*if Auth.auth().currentUser != nil {
if let uid = (Auth.auth().currentUser?.uid) {
let database = Database.database().reference()
let usuarios = database.child("usuarios").child(uid)
usuarios.observe(.value) { (snapshot) in
let dados = snapshot.value as? NSDictionary
let emailUsuario = dados?["email"] as! String
let nomeUsuario = dados?["nome"] as! String
let perfilUsuario = dados?["perfil"] as! String
let idUsuario = snapshot.key
let usuario = Usuario(email: emailUsuario, nome: nomeUsuario, uid: idUsuario, perfil: perfilUsuario)
print("Got here \(usuario.email) e \(usuario.nome) e \(usuario.uid) e \(usuario.perfil)")
if perfilUsuario != "admin" {
self.navigationItem.rightBarButtonItems?.remove(at: 1)
print("Disable + Button")
}
}
}
}*/
// Map - User location
self.mapa.delegate = self
self.gerenciadorLocalizacao.delegate = self
self.gerenciadorLocalizacao.desiredAccuracy = kCLLocationAccuracyBest
self.gerenciadorLocalizacao.requestWhenInUseAuthorization()
self.gerenciadorLocalizacao.startUpdatingLocation()
let clinicas = database.child("clinicas")
// Clinicas listeners
clinicas.observe(DataEventType.value) { (snapshots) in
for child in snapshots.children {
let snapshot = child as! DataSnapshot
print("Clinicas Mapeadas - end")
let dados = snapshot.value as? NSDictionary
//print("Dados na leitura \(dados)")
let clinica = Clinica()
clinica.identificador = snapshot.key
clinica.nome = dados?["nome"] as! String
clinica.endereco = dados?["endereco"] as! String
clinica.cidade = dados?["cidade"] as! String
clinica.cep = dados?["cep"] as! String
clinica.estado = dados?["estado"] as! String
clinica.latitude = dados?["latitude"] as! String
clinica.longitude = dados?["longitude"] as! String
clinica.urlImagem = dados?["urlImagem"] as! String
clinica.idImagem = dados?["idImagem"] as! String
self.clinicasR.append(clinica)
self.todasAnotacoes.append((objLat: Double(clinica.latitude) as! CLLocationDegrees, objLong: Double(clinica.longitude) as! CLLocationDegrees, objName: clinica.nome, objDesc: clinica.endereco, objId: clinica.identificador))
}
isClinicsLoaded = true
if (isUserLoaded && isClinicsLoaded) {
self.addAnnotationsToMap();
}
}
/* NOT IN USE FOR NOW
let latitude = Double(-23.623558)
let longitude = Double(-46.580787)
let localizacao: CLLocationCoordinate2D = CLLocationCoordinate2D.init(latitude: latitude, longitude: longitude)
let span: MKCoordinateSpan = MKCoordinateSpan.init(latitudeDelta: 0.01, longitudeDelta: 0.01)
let regiao = MKCoordinateRegion.init(center: localizacao, span: span)
self.mapa.setRegion(regiao, animated: true)*/
ProgressHUD.dismiss()
}
// add annotations to the map
func addAnnotationsToMap() {
anotacaoArray = []
for oneObject in self.todasAnotacoes {
for oneObject in self.todasAnotacoes {
// print("Oneobj \(oneObject)")
let umaAnotacao = MinhaAnotacao()
var oneObjLoc: CLLocationCoordinate2D = CLLocationCoordinate2DMake(oneObject.objLat, oneObject.objLong)
umaAnotacao.coordinate = oneObjLoc
umaAnotacao.title = oneObject.objName
umaAnotacao.subtitle = oneObject.objDesc
umaAnotacao.identicadorMapa = oneObject.objId
self.anotacaoArray.append(umaAnotacao)
print("Annotation added \(todasAnotacoes.count) - end")
}
self.mapa.addAnnotations(self.anotacaoArray)
self.todasAnotacoes = []
self.anotacaoArray = []
// print("Annotations added 2 - end")
}
}
The second observer in your code is using .childAdded, which means that closure gets called for each individual child node under clinicas. This makes it hard to know when you're done with clinics, so I recommend first switching that observer over to .value, with something like:
clinicas.observe(DataEventType.value) { (snapshots) in
for child in snapshots.children {
let snapshot = child as! DataSnapshot
let dados = snapshot.value as? NSDictionary
//print("Dados na leitura \(dados)")
let clinica = Clinica()
clinica.identificador = snapshot.key
clinica.nome = dados?["nome"] as! String
clinica.endereco = dados?["endereco"] as! String
clinica.cidade = dados?["cidade"] as! String
clinica.cep = dados?["cep"] as! String
clinica.estado = dados?["estado"] as! String
clinica.latitude = dados?["latitude"] as! String
clinica.longitude = dados?["longitude"] as! String
clinica.urlImagem = dados?["urlImagem"] as! String
clinica.idImagem = dados?["idImagem"] as! String
self.clinicasR.append(clinica)
}
// At this point we're done with all clinics
}
As you'll have notice this code now uses a loop to iterate over snapshots.children. So we're processing all child nodes of clinicas in one closure, which makes it much easier to know when we're done.
Now with the above change we have two closures that get called individually, and you have some code that you want to run when both of them are done. There are a few ways to synchronize this code.
The first way is what you've already tried: putting the clinicas.observe block into the closure of usuarios.child(idUsuarioLogado).observe(. Now that the clinics observer uses .value, you'll find that this is much easier to get working.
But I'd like to show an alternative below, where we use two simple flags to determine if both closures are done. For this you will have to put the code that runs after the data is loaded into a separate function, something like this:
func addAnnotationsToMap() }
for oneObject in self.todasAnotacoes {
...
}
}
Now in each of the two closures, we're going to set a flag when they're done. And then at the end of each of the closures, we'll detect whether both flags are set, and then call the new function if we have all data we need.
So at the start of viewDidLoad we define our two flags:
let isUserLoaded = false
let isClinicsLoaded = false
And then at the end of loading the user:
usuarios.child(idUsuarioLogado).observe(DataEventType.value) { (snapshot) in
let dados = snapshot.value as? NSDictionary
let emailUsuario = dados?["email"] as! String
let nomeUsuario = dados?["nome"] as! String
let perfilUsuario = dados?["perfil"] as! String
let idUsuario = snapshot.key
let usuario = Usuario(email: emailUsuario, nome: nomeUsuario, uid: idUsuario, perfil: perfilUsuario)
isUserLoaded = true
if (isUserLoaded && isClinicsLoaded) {
addAnnotationsToMap();
}
}
And similar code (setting the isClinicsLoaded flag) to the other closure.
With these in place, you'll start loading the user data and clinics when the code runs, and then whichever one of them completes last, will call the new addAnnotationsToMap function.
Another alternative is to use a DispatchGroup, which is an Apple-specific construct that can also make this much simpler. Read more about it in this answer (and the links from there): Wait until swift for loop with asynchronous network requests finishes executing

Save geoFire location under random firebase id swift 4

I'm trying to save the geofire information under each postId but currently not quite sure how to do so. Could someone please help me figure out how to save the information under the postId node.
#objc func handlePost() {
navigationItem.rightBarButtonItem?.isEnabled = false
guard let uid = Auth.auth().currentUser?.uid else { return }
guard let caption = textView.text, caption.characters.count > 0 else { return }
let userPostRef = Database.database().reference().child("posts").child(uid)
let ref = userPostRef.childByAutoId()
guard let locationName = locationNameButton.titleLabel?.text else { return }
let latitude = lat
let longitude = long
let geoLatitude = (latitude as! NSString).doubleValue
let geoLongitude = (longitude as! NSString).doubleValue
geoFireRef = Database.database().reference().child("posts").child(uid)
geoFire = GeoFire(firebaseRef: geoFireRef)
let values = ["caption": caption,"locationName": locationName, "latitude": latitude,"longitude": longitude,"creationDate": Date().timeIntervalSince1970] as [String : Any]
geoFire?.setLocation(CLLocation(latitude: geoLatitude, longitude: geoLongitude), forKey: ref.key!)
If you want to store the geolocation under the same key as
let ref = userPostRef.childByAutoId()
You can simply get the key property from ref. So:
geoFire?.setLocation(CLLocation(latitude: geoLatitude, longitude: geoLongitude), forKey: ref.key)

Distance from Current Location to Annotation. (Firebase)

I want to have a the distance from my Currentlocation to a annotation that's in the FireData Base. I tried to make it word but i can't ;(. I would like to have the distance between the two locations in a var. I hope you guys can help me.
func reload(){
//get data
Database.database().reference().child("Rollerbanken").observe(.value, with: { (snapshot) in
for item in snapshot.children{
if let value = snapshot.value as? Dictionary<String, Any> {
for key in value.keys {
if let itemDict = value[key] as? Dictionary<String, AnyObject> {
let annotation = MKPointAnnotation()
annotation.title = itemDict["TypeControle"] as! String
let tijd = itemDict["Tijd"] as! String
annotation.subtitle = "Geplaatst om \(tijd)"
let getLatitude = itemDict["Latitude"] as? String
let getLongitude = itemDict["Longitude"] as? String
if let lat = getLatitude, let long = getLongitude {
annotation.coordinate = CLLocationCoordinate2D(latitude: Double(lat)!, longitude: Double(long)!)
self.map.addAnnotation(annotation)
let directionRequest = MKDirectionsRequest()
directionRequest.source = MKMapItem.forCurrentLocation()
if #available(iOS 10.0, *) {
directionRequest.destination = MKMapItem(placemark: MKPlacemark.init(coordinate: CLLocationCoordinate2DMake(Double(lat)!, Double(long)!)))
} else {
// Fallback on earlier versions
}
directionRequest.transportType = .walking
let direction = MKDirections(request: directionRequest)
direction.calculate(completionHandler: { (response, error) in
if error != nil {
print("Error while build route")
} else {
let route = response?.routes.last
let distance = route?.distance
print(distance)
}
})
}
}
}
}
}
})
}
Here is my Structure:
Try to use this code. Don't forget to enable your current location on map
let directionRequest = MKDirectionsRequest()
directionRequest.source = MKMapItem.forCurrentLocation()
directionRequest.destination = MKMapItem(placemark: MKPlacemark.init(coordinate: CLLocationCoordinate2DMake(YOURPOINTLATITUDE, YOURPOINTLONGITUDE)))
directionRequest.transportType = .walking
let direction = MKDirections(request: directionRequest)
direction.calculate(completionHandler: { (response, error) in
if error != nil {
print("Error while build route")
} else {
let route = response?.routes.last
let distance = route?.distance
I have used similar function, NOTE this was my function therefore it has rider and driver.. however you can change it to use annotation and location from firebase.
if let rideRequestDictionary = snapshot.value as? [String:AnyObject] {
// Getting the rider location and email
if let email = rideRequestDictionary["email"] as? String {
if let lat = rideRequestDictionary["lat"] as? Double{
if let lon = rideRequestDictionary["lon"] as? Double{
// Getting the Driver location and email
let driverCLLocation = CLLocation(latitude: driverLocation.latitude, longitude: driverLocation.longitude)
let riderCLLocation = CLLocation(latitude: lat, longitude: lon)
// getting the distance between the two people
let distance = driverCLLocation.distance(from: riderCLLocation) / 1000
// rounding the distances
let roundedDistance = round(distance * 100) / 100
// putting the rounded distance and email in label
cell.textLabel?.text = "\(email) - \(roundedDistance)km away"
}
}
}

How can I determine if a string is natural language or an address when searching for a location?

I'm trying to implement an apple maps like search bar for users to be able to find a specific location or address and save a pin at that searched location. Now, I understand how to take an address that is in natural language and how to obtain coordinates from an address. But I have no clue how I can efficiently parse a string and know which request to make. I haven't been able to find anything online, only articles on email addresses. Any information that highlights standards / good implementations would be very appreciated!
You could use CLGeocoderto check if a string is a location. You can format your code like this:
var geocoder = CLGeocoder()
geocoder.geocodeAddressString(address) { (placemarks, error) -> Void in
if let placemark = placemarks![0] as? CLPlacemark {
print("place")
} else {
print("string")
}
}
However, this could be intensive if used on large arrays. But it should be fine for a search bar!
Thanks to both Maclean and Location Manager by Varshyl Mobile. NOTE: here is the answer I was able to come up with that sort of solves my problem; still have issues with getting the right natural language location to pop up.
let geocoder = CLGeocoder()
geocoder.geocodeAddressString(address as String, completionHandler: {(placemarks: [CLPlacemark]?, error: NSError?) -> Void in
if (error != nil) {
print("error")
}
else{
if let placemark = placemarks?.first {
let address = AddressParser()
address.parseAppleLocationData(placemark)
let addressDict = address.getAddressDictionary()
print("searched address")
print(addressDict)
}
else {
print("invalid address")
}
}
})
And Below is the class / functions that I used from the library mentioned above.
private class AddressParser: NSObject{
private var latitude = NSString()
private var longitude = NSString()
private var streetNumber = NSString()
private var route = NSString()
private var locality = NSString()
private var subLocality = NSString()
private var formattedAddress = NSString()
private var administrativeArea = NSString()
private var administrativeAreaCode = NSString()
private var subAdministrativeArea = NSString()
private var postalCode = NSString()
private var country = NSString()
private var subThoroughfare = NSString()
private var thoroughfare = NSString()
private var ISOcountryCode = NSString()
private var state = NSString()
override init(){
super.init()
}
private func getAddressDictionary()-> NSDictionary{
let addressDict = NSMutableDictionary()
addressDict.setValue(latitude, forKey: "latitude")
addressDict.setValue(longitude, forKey: "longitude")
addressDict.setValue(streetNumber, forKey: "streetNumber")
addressDict.setValue(locality, forKey: "locality")
addressDict.setValue(subLocality, forKey: "subLocality")
addressDict.setValue(administrativeArea, forKey: "administrativeArea")
addressDict.setValue(postalCode, forKey: "postalCode")
addressDict.setValue(country, forKey: "country")
addressDict.setValue(formattedAddress, forKey: "formattedAddress")
return addressDict
}
private func parseAppleLocationData(placemark:CLPlacemark){
let addressLines = placemark.addressDictionary!["FormattedAddressLines"] as! NSArray
//self.streetNumber = placemark.subThoroughfare ? placemark.subThoroughfare : ""
self.streetNumber = (placemark.thoroughfare != nil ? placemark.thoroughfare : "")!
self.locality = (placemark.locality != nil ? placemark.locality : "")!
self.postalCode = (placemark.postalCode != nil ? placemark.postalCode : "")!
self.subLocality = (placemark.subLocality != nil ? placemark.subLocality : "")!
self.administrativeArea = (placemark.administrativeArea != nil ? placemark.administrativeArea : "")!
self.country = (placemark.country != nil ? placemark.country : "")!
self.longitude = placemark.location!.coordinate.longitude.description;
self.latitude = placemark.location!.coordinate.latitude.description
if(addressLines.count>0){
self.formattedAddress = addressLines.componentsJoinedByString(", ")}
else{
self.formattedAddress = ""
}
}