I\'m using Google Places API for iOS and can successfully retrieve nearby places and present the address as a string. What I\'m trying to do is extract address components such
A safe Swift 4.2 solution:
let name = place.addressComponents?.first(where: { $0.type == "city" })?.name
selectedPlace.addressComponents is a array of GMSAddressComponent which have 2 properties type and name. In you case it will be like
for component in addressComponents! {
if component.type == "city" {
print(component.name)
}
}
GMSAddressComponent is a class not a dictionary or array that's you are getting this error.
Additional component types can be referred from the link.
Swift 4
var keys = [String]()
place.addressComponents?.forEach{keys.append($0.type)}
var values = [String]()
place.addressComponents?.forEach({ (component) in
keys.forEach{ component.type == $0 ? values.append(component.name): nil}
})
print(values)
I am using this extension:
extension Array where Element == GMSAddressComponent {
func valueFor(placeType: String, shortName: Bool = false) -> String? {
// bug in the google or apple framework. This cast must stay.
// Withou it crashing.
guard let array = self as? NSArray else { return nil }
let result = array
.compactMap { $0 as? GMSAddressComponent }
.first(where: {
$0.types
.first(where: { $0 == placeType }) == placeType
})
return shortName ? result?.shortName : result?.name
}
}
Usage:
let place: GMSPlace
// ...
place.addressComponents?.valueFor(placeType: kGMSPlaceTypeRoute, shortName: true)
It's working in Swift 5 and iOS 13.3
1. Create a function for showing GMSAutocompleteViewController
func googlePlacesSearchVC() {
let acController = GMSAutocompleteViewController()
acController.delegate = self
// Specify the place data types to return.
let fields: GMSPlaceField = GMSPlaceField(rawValue: UInt(GMSPlaceField.name.rawValue) |
UInt(GMSPlaceField.formattedAddress.rawValue) |
UInt(GMSPlaceField.addressComponents.rawValue))!
acController.placeFields = fields
// Specify a filter.
let filter = GMSAutocompleteFilter()
filter.country = "IN"
acController.autocompleteFilter = filter
acController.secondaryTextColor = .darkGray
acController.primaryTextColor = .lightGray
acController.primaryTextHighlightColor = .black
acController.tableCellBackgroundColor = .whiteThree
acController.tableCellSeparatorColor = .lightGray
// Display the autocomplete view controller.
present(acController, animated: true) {
let views = acController.view.subviews
let subviewsOfSubview = views.first!.subviews
let subOfNavTransitionView = subviewsOfSubview[1].subviews
let subOfContentView = subOfNavTransitionView[1].subviews
let searchBar = subOfContentView[0] as! UISearchBar
searchBar.searchTextField.placeholder = "places_picker_hint_add_address".localized
searchBar.searchBarStyle = .minimal
searchBar.searchTextField.font = UIFont.screenTitle16Pt
searchBar.searchTextField.backgroundColor = UIColor.white
searchBar.searchTextField.leftView?.tintColor = .darkGray
searchBar.delegate?.searchBar?(searchBar, textDidChange: "")
}
}
2. Call that function where ever you need, for ex:-
override func viewDidLoad() {
super.viewDidLoad()
googlePlacesSearchVC()
}
3. Call GMSAutoCompleteViewControllerDelegates Methods. Here will get all details like Street, City, etc. from GMSPlace Address Components
extension ViewController {
// Handle the user's selection.
func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
// Show HouseAndFlat
if place.name?.description != nil {
yourTxtField.text = place.name?.description ?? ""
}
// Show latitude
if place.coordinate.latitude.description.count != 0 {
var latitude = place.coordinate.latitude
}
// Show longitude
if place.coordinate.longitude.description.count != 0 {
selectedLongitude = place.coordinate.longitude
}
// Show AddressComponents
if place.addressComponents != nil {
for addressComponent in (place.addressComponents)! {
for type in (addressComponent.types){
switch(type){
case "sublocality_level_2":
yourTxtField.text = addressComponent.name
case "sublocality_level_1":
yourTxtField.text = addressComponent.name
case "administrative_area_level_2":
yourTxtField.text = addressComponent.name
case "administrative_area_level_1":
yourTxtField.text = addressComponent.name
case "country":
yourTxtField.text = addressComponent.name
case "postal_code":
yourTxtField.text = addressComponent.name
default:
break
}
}
}
}
dismiss(animated: true, completion: nil)
}
func viewController(_ viewController: GMSAutocompleteViewController, didFailAutocompleteWithError error: Error) {
// TODO: handle the error.
print("Error: ", error.localizedDescription)
}
// User canceled the operation.
func wasCancelled(_ viewController: GMSAutocompleteViewController) {
dismiss(animated: true, completion: nil)
}
}
I have found an answer from this link