Ios Swift Place Photo with google places sdk - ios

I want to show the first photo of the place with the geo-coordinates from google API but I am not getting any proper way. But what I got is https://developers.google.com/places/ios-api/photos now this needs Place-id I am even unable to find place-id with geo-coordinates. Can anyone tell me how can I extract photos of the place with geo-coordinate? Any Help would be appreciated.

You should first search first for the place with the API.
The response contains an 'placeID', now you can use this ID in your 2nd request.

try this
func loadFirstPhotoForPlace(placeID: String) {
GMSPlacesClient.shared().lookUpPhotos(forPlaceID: placeID) { (photos, error) -> Void in
if let error = error {
// TODO: handle the error.
print("Error: \(error.localizedDescription)")
} else {
if let firstPhoto = photos?.results.first {
self.loadImageForMetadata(photoMetadata: firstPhoto)
}
}
}
}

Related

Swift: how to detect the error type using the debugger?

I'm new in iOS development, so maybe I'm thinking in the wrong way. I coded a view model with a function that calls an API, and everything works fine.
class SearchCityViewModel : ViewModelProtocol {
//OBSERVABLES
var cities = PublishSubject<[City]>()
var networkError = PublishSubject<Void>()
var generalError = PublishSubject<Void>()
init(){
print("Init SearchCityViewModel")
reinit()
}
func reinit(){}
func searchCity(stringToSearch: String){
async {
do {
if stringToSearch.count>=2 {
let cities = try await(api.getCities(cityToSearch: stringToSearch)).payload!
self.cities.onNext(cities)
}
else {
self.cities.onNext([])
}
}
catch {
self.generalError.onNext(Void())
}
}
}
Now I want to handle errors. In the catch block I want to distinguish all the errors I want to handle gracefully, and for the other ones I just want to emit a general error. To do that, firstly I need to know which error is thrown when the situation I want to handle occurs. I usually do this with the debugger. For instance, I disable the internet connection, and i create a breakpoint inside the catch block. The idea is to check which error is thrown when the internet connection is disabled, in order to create a catch block for that kind of error.
Image of the debugger
I'm struggling because with the debugger I only see that is an AFError instance, but it's not telling me nothing more that can help me to catch it.
What is wrong with my workflow? Do I really need to read all the docs every time? For each library I use?
Thank you!
Perhaps you can read the articles and then you will know how to do it better, you can use the framework -oslog instead of using print function.
debugging your logging info
I found the way. What I was missing is casting the error as NSError. In this way, with the debugger is possible to see the domain and the code of the error. In the case of Alamofire, the real error is wrapped, and it's accessible through the underlyingError attribute. Once I had the domain and the code of the error, I wrote the following code:
class SearchCityViewModel : ViewModelProtocol {
//OBSERVABLES
var cities = PublishSubject<[City]>()
var networkError = PublishSubject<Void>()
var generalError = PublishSubject<Void>()
init(){
print("Init SearchCityViewModel")
reinit()
}
func reinit(){}
func searchCity(stringToSearch: String){
async {
do {
if stringToSearch.count>=2 {
let cities = try await(api.getCities(cityToSearch: stringToSearch)).payload!
self.cities.onNext(cities)
}
else {
self.cities.onNext([])
}
}
catch {
if let afError = asAFError, let underlyingError = afError.underlyingError as NSError?, underlyingError.domain == NSURLErrorDomain, underlyingError.code == NSURLErrorNotConnectedToInternet || underlyingError.code == NSURLErrorTimedOut {
self.networkError.onNext(Void())
}
else {
self.generalError.onNext(Void())
}
}
}
}

CloudKit: Get users firstname/surname

I'm trying to get the users first name using cloud kit however the following code is not getting the users first name and is leaving firstNameFromFunction variable empty. Does anyone know how to achieve this in iOS 10?
let container = CKContainer.default()
container.fetchUserRecordID { (recordId, error) in
if error != nil {
print("Handle error)")
}else{
self.container.discoverUserInfo(
withUserRecordID: recordId!, completionHandler: { (userInfo, error) in
if error != nil {
print("Handle error")
}else{
if let userInfo = userInfo {
print("givenName = \(userInfo.displayContact?.givenName)")
print("familyName = \(userInfo.displayContact?.familyName)")
firstNameFromFunction = userInfo.displayContact?.givenName
}else{
print("no user info")
}
}
})
}
}
the permission screen that comes up when asking for the first time, IMO, is very poorly worded. They need to change that. It says "Allow people using 'your app' to look you up by email? People who know your email address will be able to see that you use this app." This make NO sense. This has nothing to do with asking the user to get their iCloud first name, last name, email address.
Speaking of email address - this and the phone number from the lookupInfo property is missing - i.e. set to nil, even though those values are legit and correct. Filing a bug tonight.
First, you will need to request permission to access the user's information.
Then, you can use a CKDiscoverUserIdentitiesOperation. This is just like any other CKOperation (eg. the modify record operation). You just need to create a new operation with the useridentitylookupinfo. Then you will also need to create a completion block to handle the results.
Here is an example function I created:
func getUserName(withRecordID recordID: CKRecordID,
completion: #escaping (String) -> ()) {
if #available(iOS 10.0, *) {
let userInfo = CKUserIdentityLookupInfo(userRecordID: recordID)
let discoverOperation = CKDiscoverUserIdentitiesOperation(userIdentityLookupInfos: [userInfo])
discoverOperation.userIdentityDiscoveredBlock = { (userIdentity, userIdentityLookupInfo) in
let userName = "\((userIdentity.nameComponents?.givenName ?? "")) \((userIdentity.nameComponents?.familyName ?? ""))"
completion(userName)
}
discoverOperation.completionBlock = {
completion("")
}
CKContainer.default().add(discoverOperation)
} else {
// iOS 10 and below version of the code above,
// no longer works. So, we just return an empty string.
completion("")
}
}
First you need to ask the user for permission to be discovered.
Use CKContainer.default().requestApplicationPermission method passing .userDiscoverability on applicationPermission parameter.
The CKContainer.default().discoverUserInfo method is deprecated on iOS 10. Instead use CKContainer.default().discoverUserIdentity method.
Do something like:
CKContainer.default().requestApplicationPermission(.userDiscoverability) { (status, error) in
CKContainer.default().fetchUserRecordID { (record, error) in
CKContainer.default().discoverUserIdentity(withUserRecordID: record!, completionHandler: { (userIdentity, error) in
print("\(userIdentity?.nameComponents?.givenName)")
print("\(userIdentity?.nameComponents?.familyName)")
})
}
}

nested asynchronous fetches with Cloudkit?

I am relatively new to coding for iOS. In the past week, I've been incorporating CloudKit into my project. One thing I want to do is get the current User recordID. Then, using that recordID, I want to fetch that user's actual record. Currently I am using the following code, which seems to work:
self.container.fetchUserRecordID() { recordID, error in
if error == nil {
self.userRecordID = recordID
DispatchQueue.main.async(execute: {
self.db.fetch(withRecordID: self.userRecordID) { record, error in
if error == nil {
self.userRecord = record
} else {
if let error = error as? CKError {
print(error)
}
}
}
})
}
else {
if let error = error as? CKError {
print(error)
}
}
}
This, however, feels messy to me. My question is two-fold: 1) In general, is it acceptable to nest asynchronous calls? 2) If not, is there a better way to accomplish what I want to do in this situation?
Thanks!

CNContactVCardSerialization.dataWithContacts giving exception

I'm trying to convert a CNContact array to vCard using the method CNContactVCardSerialization.dataWithContacts(). But it is giving me the following error.
2016-07-25 14:05:00.115 AddressBook-ios9[902:28918] Exception writing contacts to vCard (data): A property was not requested when contact was fetched.
I made sure that I'm passing an valid array of CNContacts, but still it is giving this exception. Can anybody guide to me to what I've done wrong?
I'm attaching the source code below.
func getVcardFromSearchingName(name: String) -> NSData? {
do {
if let contacts = searchMultiContacts(name) {
print(contacts)
let vCard = try CNContactVCardSerialization.dataWithContacts(contacts)
return vCard
} else {
return nil
}
} catch {
return nil
}
}
I found out my mistake. On the keys to fetch contact, I was missing CNContactVCardSerialization.descriptorForRequiredKeys(). After adding it, the code is working flawlessly.

Parse iOS - How to capture the findObjects() error being thrown?

I am coding in Swift and attempting to use the findObjects() function for the Parse iOS SDK. However, I can't seem to figure out what type of error is being thrown by Parse if this function call fails. I'm a novice in Swift so that may be my issue. I attempt to call the function in a do->catch block and use the try keyword on the function call however I'm not sure what to catch. I can catch the error using the _ but I would like to grab the description from the error. Thanks!
P.S. I don't want to use the findObjectsInBackground() method.
do {
let object = try query.getFirstObject()
// do something with the object
} catch _ {
// this is where I would like to print out the error description
}
In Obj-C, which I assume will be similar, I print out the error.userInfo[#"error"] parameter of the NSError that is returned.
All you need is print(error). An example here:
func getReferenceNumberAsStringSync() -> String? {
let query = PFQuery(className: "PropertyCount")
do {
let object = try query.getFirstObject()
if let referenceNumber = object["count"] as? Int {
return String(referenceNumber)
}
} catch {
print(error)
}
return nil
}

Resources