Is there a way to let a user change their location by searching for a place? - swift

I'm making an app in XCode similar to Yelp where it displays nearby restaurants based on the user's location. I would like to add a feature where the user can search for a location and the app will respond by showing restaurants at that location instead of the user's current location. The app pulls the user's location and displays restaurants with this code: locationService.newLocation = { [weak self] result in switch result { case .success(let location): self?.loadBusinesses(with: location.coordinate) case .failure(let error): print(error.localizedDescription) }
"coordinate" is a var: open var coordinate: CLLocationCoordinate2D { get }
Is there a way to let the user search for a location to change "coordinate" and replace it with the location they searched? I'm somewhat new to coding, so this might not be enough information, please let me know if I'm missing some information.

Related

Health Kit: How to set 'totalEnergyBurned' for workout?

Today I worked for the first time with Apple Health Kit and successfully saved a workout in Health with the basic informations (activityType, start and end).
My app is in basic function an interval timer where you can create your own workout. Now in the next step I want to add the calories burned in the workout. This information is stored in the attribute 'totalEnergyBurned'.
Do I need to calculate this value myself or can I query this value directly if the user is wearing an Apple Watch? Or maybe the value is even automatically added to the workout if there is the corresponding record? (So far I have only tested the app in the simulator, which is why I can't answer this possibility).
My current code:
func saveToHealthKit(entryID: String){
if HKHealthStore.isHealthDataAvailable() {
let healthStore = HKHealthStore()
if(healthStore.authorizationStatus(for: HKObjectType.workoutType()) == .sharingAuthorized && healthStore.authorizationStatus(for: HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.activeEnergyBurned)!) == .sharingAuthorized){
let newWorkout = HKWorkout(activityType: HKWorkoutActivityType.highIntensityIntervalTraining, start: entry.date!, end: Date())
healthStore.save(newWorkout) { success, error in
guard success else {
// Perform proper error handling here.
return
}
// Add detail samples here.
}
}
}
}
}
Thanks :)
I am not sure I understood your case correctly, but if the user is using an Apple Watch and does a workout you can query HealthKit for an HKWorkout object, which holds a totalEnergyBurned attribute.
If you are not querying this HKWorkout object, then I believe you can query for the activeEnergyBurned quantity type using the start and end date-time of the user workout in the predicate.

geoFire .getLocation using Firebase and need an observe to monitor changes as they occur, Swift

I am using GeoFire in Swift and am able to .setLocation for a user and .getLocation I can retrieve their location and it all works good, i can then create an annotation and also create a poly line to a destination.
What I would now like to do is to move the user location along the polyline as the user travels.
To do this I was wondering how can I setup a Firebase.observe to let me know when the user moves and the map will auto update
The code I use for getLocation (snippet)
func fetchTradeLocationTest() {
guard let uid = tradeUser?.uid else { return }
let geoFire = GeoFire(firebaseRef: DB_REF.child("tradelocation"))
geoFire.getLocationForKey(uid) { (location, error) in
if (error != nil) {
print("DEBUG: An error occurred getting the location for \"tradeLocation\": \(error?.localizedDescription)")
} else if (location != nil) {
print("DEBUG: location = \(location)")
} else {
print("DEBUG: GeoFire does not contain a location for \"tradeLocation\"")
}
}
}
Wonder if anyone can guide me on how to set it up as an observer such that i get updated position.
Appreciate any help
GeoFire adds the ability to run geoqueries on Firebase, which means that you can find the keys that are in a certain geographic range and detect the data in it, and changes to that data.
In your specific use-case, you already know the key that you want to monitor. This mens you don't need a geoquery, but instead can use the regular observe API of the Realtime Database to monitor that specific key:

CLGeocoder().geocodeAddressString error codes

I am working on a project where I use CLGeocoder to determine the placemarks for a particular location.
Very simple call like this.
CLGeocoder().geocodeAddressString(location) { (placemarks, error) in
if let error = error {
print(error.localizedDescription)
}
Instead of printing out the NSError's localizedDescription, I would like to be able to capture the CLError code and respond accordingly. For example, if the location can't be found, my localizedDescription prints
The operation couldn’t be completed. (kCLErrorDomain error 8.)
How can I, in Swift determine the CLError code so that I do not have to switch on some localized description that will change based on user's locale?
Can this be done?
I only have a couple of cases that I want to switch on.
You need to cast the error as CLError and then switch the error code:
if let error = error as? CLError {
switch error.code {
case .locationUnknown:
print("locationUnknown: location manager was unable to obtain a location value right now.")
case .denied:
print("denied: user denied access to the location service.")
case .promptDeclined:
print("promptDeclined: user didn’t grant the requested temporary authorization.")
case .network:
print("network: network was unavailable or a network error occurred.")
case .headingFailure:
print("headingFailure: heading could not be determined.")
case .rangingUnavailable:
print("rangingUnavailable: ranging is disabled.")
case .rangingFailure:
print("rangingFailure: a general ranging error occurred.")
default : break
}
}

Unique ID of MKLocalSearch result?

My App shows the result of a MKLocalSearch query.
The user can select such a place and say 'I like this place'.
When the user searches again (after closing the App), how can my App know that the user already likes this place?
Is there something in the result that does not depend on the locale (the same at the next search) and unique (not shared by another place at the same location)
let request = MKLocalSearchRequest()
request.region = mapView.region
request.naturalLanguageQuery = query
let search = MKLocalSearch(request: request)
search.start { (response, error) in
// do I know some items in the response?
}
You should get the phone number back as part of the response, which you can use as a unique ID for the location.

Swift OSX CNContact.organizationName crash in High Sierra

My OSX app allows the user to select a contact from their contacts list and loads the details into a Customer record. I am using CNContactPicker to retrieve a contact into a CNContact record. One of the fields I need to retrieve is organizationName. This works perfectly in OS's prior to High Sierra, but upon upgrading to High Sierra it will crash. All other CNContact fields can be retrieved with no issue (e.g. names, email, address etc). I do have permissions requested in my info.plist file.
It makes no difference if the Contact does/does not have an Organization Name.
Not much to show in terms of code:
// This fails on 1st line - any reference to organizationName causes failure
if (contact.organizationName != "") {
self.name = contact.organizationName
}
// This works
if (contact.givenName != "") {
self.name = contact.givenName
}
// This works
if (contact.contactType == CNContactType.organization) {
// Do something
}
The actual error is: [General] A property was not requested when contact was fetched.
I would like to know what has changed in the OS to cause this error, and if there is a solution or workaround please.
I submitted a bug report with Apple and received the following response which fixes my issue. Essentially, even though I have retrieved a Contact that the user selected, I need to do a CNContactFetchRequest to fetch this specific contact again (using the identifier) with keys specified (e.g. organisation).
Here is their exact response:
If you want to make sure organizationName is available, execute a CNFetchRequest for a contact with the same identifier (as returned from CNContactPicker delegate method) and provide a set of keys to fetch containing CNContactOrganizationName.
Here is the code:
var validContacts: [CNContact] = []
let contactStore = CNContactStore()
do {
// Specify the key fields that you want to be fetched.
// Note: if you didn't specify your specific field request. your app will crash
let fetchRequest = CNContactFetchRequest(keysToFetch: [CNContactOrganizationNameKey as CNKeyDescriptor])
fetchRequest.predicate = CNContact.predicateForContacts(withIdentifiers: [contact.identifier])
try contactStore.enumerateContacts(with: fetchRequest, usingBlock: { (contact, error) -> Void in
validContacts.append(contact)
})
for validContact in validContacts {
// Do something with your contact, there should be only one.
}
} catch let e as NSError {
print(e)
}