【问题标题】:How to extract street, city, etc. from GMSPlace Address Components如何从 GMSPlace 地址组件中提取街道、城市等
【发布时间】:2017-10-22 02:50:16
【问题描述】:

我正在使用适用于 iOS 的 Google Places API,并且可以成功检索附近的地点并将地址显示为字符串。我正在尝试做的是提取地址组件(例如城市)以存储在数据库中。

文档表明 GMSPlace 有一个 addressComponents 属性(一个数组),但我似乎不知道如何使用这个属性。

下面的代码将整个地址设置为标签的文本,但我无法超越:

编辑 ---- 添加了显示我如何尝试访问地址组件的代码

venueLabel.isHidden = false
            venueLabel.text = selectedPlace?.name
            addressLabel.isHidden = false
            addressLabel.text = selectedPlace?.formattedAddress
            let addressComponents = selectedPlace?.addressComponents
            for component in addressComponents! {
                let city = component["city"] //Error Type GMSPaceAddressComponent has no subscript members
                print(city)
            }

【问题讨论】:

  • 请分享完整代码。
  • API 文档中提到了addressComponents 的所有详细信息。看到这个developers.google.com/places/ios-api/reference/…
  • @Shabirjan 刚刚使用附加代码进行了编辑
  • 您需要检查 component.type == "city" 然后检索 component.name 以获取城市信息
  • 让 addressComponent = place?.addressComponents?.first(where: {$0.types.contains("city")})

标签: ios swift3 google-places-api


【解决方案1】:

一个安全的 Swift 4.2 解决方案:

let name = place.addressComponents?.first(where: { $0.type == "city" })?.name

selectedPlace.addressComponents 是一个 GMSAddressComponent 数组,它有 2 个属性类型和名称。 在你的情况下,它会像

    for component in addressComponents! {
    if component.type == "city" {
    print(component.name)
    }
   }

GMSAddressComponent 是一个类而不是字典或数组,您会收到此错误。

其他组件类型可以参考link

【讨论】:

  • 谢谢。现在它完全有道理。干杯!
  • @FadiAbuzant 没错。我对此答案的更改待定,但在此之前,请在 GMSAddressComponent 上使用 types 数组属性而不是 type。检查该数组是否包含 kGMSPlaceTypeLocality 类型。不同的 GMSPlaceTypes 在 Google Places SDK for iOS v3.1.0 的 GMSPlaceTypes.h 中定义。编码愉快!
  • @FateNuller 请更新此答案。我会确保你的回答会出现在这里。
  • @SurjeetRajput 我的编辑被两位审阅者拒绝,原因相同:“这个编辑偏离了帖子的初衷。即使是必须做出重大改变的编辑也应该努力保持帖子的目标所有者。”考虑到我的编辑只更新了现有内容以便与最新版本的 Google Places API 相关,这对我来说听起来并不准确。由于这篇文章没有指定版本,我认为假设最新版本是合理的。
  • type 属性现在被弃用,取而代之的是 types
【解决方案2】:

我在 Objective-C 的任何地方都找不到这个,对于那些追随我的人:

for (int i = 0; i < [place.addressComponents count]; i++)
{
    NSLog(@"name %@ = type %@", place.addressComponents[i].name, place.addressComponents[i].type);
}

【讨论】:

    【解决方案3】:
    for ( GMSAddressComponent * component in place.addressComponents) {
        if ( [component.type  isEqual: @"locality"] )
        {
            NSLog(@"Current city %@ ", component.name);
        }
    }
    

    【讨论】:

    • 虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。
    • 请解释为什么您的代码可以解决问题。仅代码答案对社区没有用处。
    【解决方案4】:

    斯威夫特 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) 
    

    【讨论】:

      【解决方案5】:
      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("All component type \(component.type)")
      
             if component.type == "locality"{
                  print("This is city name \(component.name)")
              }
          })
          print(values)
      

      【讨论】:

        【解决方案6】:

        我找到了,希望能帮到你

          let arrays : NSArray = place.addressComponents! as NSArray
                for i in 0..<arrays.count {
        
                    let dics : GMSAddressComponent = arrays[i] as! GMSAddressComponent
                    let str : NSString = dics.type as NSString
        
                    if (str == "country") {
                        print("Country: \(dics.name)")
                        self.pais = dics.name
                    }
        
                    else if (str == "administrative_area_level_2") {
                        print("City: \(dics.name)")
                        self.ciudad = dics.name
                    }
        

        【讨论】:

          【解决方案7】:

          对于最新的 Google Places API(2019 年 7 月),这可以为您提供帮助。 实际上,谷歌现在为每个元素添加了几种类型。所以“类型”现在已被弃用,“类型”是新文件。

          你可以这样做:

           for addressComponent in (self.mySelectedPlace?.addressComponents)! {
                      for type in (addressComponent.types){
          
                          switch(type){
                              case "country":
                                  var country = addressComponent.name
          
                              case "postal_code":
                                   var postCode = addressComponent.name
          
                          default:
                              break
                          }
          
                      }
                  }
          

          【讨论】:

            【解决方案8】:

            我正在使用这个扩展:

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

            用法:

            let place: GMSPlace
            // ...
            place.addressComponents?.valueFor(placeType: kGMSPlaceTypeRoute, shortName: true)
            

            【讨论】:

            • 线程 1:前提条件失败:NSArray 元素未能匹配 Swift Array 元素类型
            • @EgzonArifi 我确实对扩展进行了更改。请立即查看。
            • 好一个@Ramis
            【解决方案9】:

            我将扩展@Ramis 的答案,在任何情况下您都想检查多种类型(如果其中一种存在),例如

            addressComponents?.valueFor(placeTypes: kGMSPlaceTypePostalTown, kGMSPlaceTypeLocality)
            

            实现

            extension Array where Element == GMSAddressComponent {
                func valueFor(placeTypes: String..., shortName: Bool = false) -> String? {
                    let array = self as NSArray
                    let result = array
                        .compactMap { $0 as? GMSAddressComponent }
                        .first(where: {
                            placeTypes.contains($0.types.first(where: { placeTypes.contains($0) }) ?? "")
                        })
                    return shortName ? result?.shortName : result?.name
                }
            }
            

            【讨论】:

            • 太搞笑了!我将再次学习本课程,以恢复 GeoLocation 的速度。谢谢!!
            【解决方案10】:

            它适用于 Swift 5 和 iOS 13.3

            1.创建一个显示 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。在需要时调用该函数,例如:-

               override func viewDidLoad() {
                  super.viewDidLoad()
            
                  googlePlacesSearchVC()
               }
            

            3.调用 GMSAutoCompleteViewControllerDelegates 方法。 这里将从 GMSPlace 地址组件中获取所有详细信息,例如街道、城市等

            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

            【讨论】:

            • 如何从 GMSPlace 找到街道地址和公寓/套房??
            • @SilverskyTechnology print("addressComponents :-", place.addressComponents as Any) 您将获得数组列表。你需要什么检查一下。
            猜你喜欢
            • 2018-01-25
            • 1970-01-01
            • 2011-02-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-03-25
            • 1970-01-01
            相关资源
            最近更新 更多