【问题标题】:How to get formatted address NSString from AddressDictionary?如何从 AddressDictionary 获取格式化的地址 NSString?
【发布时间】:2011-10-21 10:42:00
【问题描述】:

试图从我从 CLGeocoder 获得的 AddressDictionary 获取格式化地址。 使用以下代码没有结果:

subtitle = [NSString stringWithString:[[addressDict objectForKey:@"FormattedAddressLines"]objectAtIndex:0]];

也试过了:

subtitle = [[[ABAddressBook sharedAddressBook] formattedAddressFromDictionary:placemark.addressDictionary] string];

但此代码似乎仅适用于 Mac OS X。

编译器询问 ABAdressBook,但我已导入两个头文件。

#import <AddressBook/ABAddressBook.h>
#import <AddressBook/AddressBook.h>

【问题讨论】:

    标签: ios addressbook clgeocoder


    【解决方案1】:

    addressDictionary 属性的文档说:

    您可以格式化此字典的内容以获取完整地址 字符串而不是自己构建地址。要格式化 字典,使用 ABCreateStringWithAddressDictionary 函数作为 地址簿 UI 函数参考中描述。

    所以添加并导入AddressBookUI 框架并尝试:

    subtitle = 
        ABCreateStringWithAddressDictionary(placemark.addressDictionary, NO);
    

    【讨论】:

    • 这是正确的使用方法...但是它并不总是提供完整的地址。例如,使用 CLGeocoder 查找“华尔街”将返回一个地标,并在地标字典上调用 ABCreateStringWithAddressDictionary 将返回“纽约,纽约,美国”......并且找不到“华尔街”。
    • 这个方法还添加了奇怪的ascii字符,最后在iOS8中检查
    • fyi - ABCreateStringWithAddressDictionary 在 iOS 9.0 中已被弃用
    • addressDictionary 在 iOS 11 中已弃用。
    【解决方案2】:

    在 iOS 6.1 下做了一些挖掘后,我发现 CLPlacemark 地址字典包含一个预先格式化的地址:

    CLLocation *location = [[CLLocation alloc]initWithLatitude:37.3175 longitude:-122.041944];
    [[[CLGeocoder alloc]init] reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
        CLPlacemark *placemark = placemarks[0];
        NSArray *lines = placemark.addressDictionary[ @"FormattedAddressLines"];
        NSString *addressString = [lines componentsJoinedByString:@"\n"];
        NSLog(@"Address: %@", addressString);
    }];
    

    我还找不到有关此的文档,但它适用于我测试的所有地址。

    【讨论】:

    • 和问题一样。
    • 是的,但你说它不起作用。我在所有设备和模拟器上的测试表明它确实有效。至少使用最新的 iOS 版本。
    • 这是一个很好的答案,但为了让我获得完整的地址,我不得不改用它NSString *addressString = [lines componentsJoinedByString:@", "];
    • @DigitalChild 您可以通过任何字符串加入行。我猜你没有看到完整的地址,因为我使用了换行符。
    • 当我在帕洛阿尔托搜索“Apple”时,我得到了两个 Apple Store 结果。在其addressDictionary 中也没有"FormattedAddressLines" 键。
    【解决方案3】:

    正如 Martyn Davis 所强调的,ABCreateStringWithAddressDictionary 在 iOS 9 中已被弃用。

    您可以使用下面的函数将addressDictionary转换为较新的CNMutablePostalAddress,然后只要导入Contacts框架,就可以使用CNPostalAddressFormatter生成本地化字符串。

    斯威夫特 3.x

    // Convert to the newer CNPostalAddress
    func postalAddressFromAddressDictionary(_ addressdictionary: Dictionary<NSObject,AnyObject>) -> CNMutablePostalAddress {
       let address = CNMutablePostalAddress()
    
       address.street = addressdictionary["Street" as NSObject] as? String ?? ""
       address.state = addressdictionary["State" as NSObject] as? String ?? ""
       address.city = addressdictionary["City" as NSObject] as? String ?? ""
       address.country = addressdictionary["Country" as NSObject] as? String ?? ""
       address.postalCode = addressdictionary["ZIP" as NSObject] as? String ?? ""
    
       return address
    }
    
    // Create a localized address string from an Address Dictionary
    func localizedStringForAddressDictionary(addressDictionary: Dictionary<NSObject,AnyObject>) -> String {
        return CNPostalAddressFormatter.string(from: postalAddressFromAddressDictionary(addressDictionary), style: .mailingAddress)
    }
    

    斯威夫特 2.x

    import Contacts
    
    // Convert to the newer CNPostalAddress
    func postalAddressFromAddressDictionary(addressdictionary: Dictionary<NSObject,AnyObject>) -> CNMutablePostalAddress {
    
        let address = CNMutablePostalAddress()
    
        address.street = addressdictionary["Street"] as? String ?? ""
        address.state = addressdictionary["State"] as? String ?? ""
        address.city = addressdictionary["City"] as? String ?? ""
        address.country = addressdictionary["Country"] as? String ?? ""
        address.postalCode = addressdictionary["ZIP"] as? String ?? ""
    
        return address
    }
    
    // Create a localized address string from an Address Dictionary
    func localizedStringForAddressDictionary(addressDictionary: Dictionary<NSObject,AnyObject>) -> String {
    
        return CNPostalAddressFormatter.stringFromPostalAddress(postalAddressFromAddressDictionary(addressDictionary), style: .MailingAddress)
    }
    

    【讨论】:

    • 注:此 API 在 iOS9 以上可用。
    • 谢谢。仅供参考,CNPostalAddressFormatter.stringFromPostalAddress 的文档没有提及第二个 style 参数,但除非您拥有它,否则构建会失败。查看文档:developer.apple.com/library/ios/documentation/Contacts/…:
    • “ZIP”的使用不是只针对美国地址吗?
    • addressDictionary 包括ZIP 字段只是地理编码器返回结果的格式。ZIP 是字段的名称,但地理编码器放置等效值(如邮政编码)据我所知,在适用的情况下进入这个领域。我不住在美国,它对我有用。
    • CNPostalAddressFormatter 似乎没有在字符串中包含分隔符。例如,对于美国地址,城市和州之间没有逗号。有没有办法启用它?
    【解决方案4】:
    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        // get the address
        if let location = locations.last {
            CLGeocoder().reverseGeocodeLocation(location, completionHandler: { (result: [CLPlacemark]?, err: NSError?) -> Void in
                if let placemark = result?.last
                    , addrList = placemark.addressDictionary?["FormattedAddressLines"] as? [String]
                {
                    let address =  addrList.joinWithSeparator(", ")
                    print(address)
                }
            })
        }
    }
    

    以上是 swift 版本。

    【讨论】:

    • 显然 addressDictionary 的下标在 iOS 9 中不再起作用
    • @FredA。我已将代码更新为最新的 swift 语法。
    • 自 2017 年 2 月 3 日起,swift 要求在 addrList 和 joinWithSeparator 前增加一个额外的 let。
    • 为什么获取地标需要两到三秒
    【解决方案5】:

    我正在使用 Swift 3 / XCode 8

    ZYiOS's answer 很好很短,但没有为我编译。

    问题询问如何从现有的地址字典中获取字符串地址。这就是我所做的:

    import CoreLocation
    
    func getAddressString(placemark: CLPlacemark) -> String? {
        var originAddress : String?
    
        if let addrList = placemark.addressDictionary?["FormattedAddressLines"] as? [String]
        {
            originAddress =  addrList.joined(separator: ", ")
        }
    
        return originAddress
    }
    

    【讨论】:

      【解决方案6】:

      Swift 3 / Xcode 8 Helper Mehtod 从 CLPlaceMark 获取地址

      class func formattedAddress(fromPlacemark placemark: CLPlacemark) -> String{
          var address = ""
      
          if let name = placemark.addressDictionary?["Name"] as? String {
              address = constructAddressString(address, newString: name)
          }
      
          if let city = placemark.addressDictionary?["City"] as? String {
              address = constructAddressString(address, newString: city)
          }
      
          if let state = placemark.addressDictionary?["State"] as? String {
              address = constructAddressString(address, newString: state)
          }
      
          if let country = placemark.country{
            address = constructAddressString(address, newString: country)
          }
      
          return address
        }
      

      【讨论】:

        【解决方案7】:

        现在这很简单

        func updateUserAddress(coordinates: CLLocationCoordinate2D) {
            let geoCoder = CLGeocoder()
            let location = CLLocation(latitude: coordinates.latitude, longitude: coordinates.longitude)
            geoCoder.reverseGeocodeLocation(location) {[weak self] (placemarks, error) in
                if error == nil, let placemark = placemarks?.first, let address = placemark.postalAddress {
                    self?.userLocationLabel.text = CNPostalAddressFormatter.string(from: address, style: .mailingAddress)
                }
            }
        }
        

        【讨论】:

          【解决方案8】:

          iOS 11+

          import CoreLocation
          import Contacts
          
          public extension CLPlacemark {
              func formattedAddress() -> String? {
                  guard let postalAddress = postalAddress else { return nil }
                  let formatter = CNPostalAddressFormatter()
                  formatter.style = .mailingAddress
                  let formatterString = formatter.string(from: postalAddress)
                  return formatterString.replacingOccurrences(of: "\n", with: " ")
              }
          }
          

          【讨论】:

            【解决方案9】:

            只需为CLLocation 创建扩展:

            typealias AddressDictionaryHandler = ([String: Any]?) -> Void
            
            extension CLLocation {
            
                func addressDictionary(completion: @escaping AddressDictionaryHandler) {
            
                    CLGeocoder().reverseGeocodeLocation(self) { placemarks, _ in
                        completion(placemarks?.first?.addressDictionary as? [String: AnyObject])
                    }
                }
            }
            

            例子:

            let location = CLLocation()
            
            location.addressDictionary { dictionary in
            
                let city = dictionary?["City"] as? String
                let street = dictionary?["Street"] as? String
            }
            

            【讨论】:

              【解决方案10】:

              Swift 5 版本

              CLGeocoder().reverseGeocodeLocation(newLocation!, preferredLocale: nil) { (clPlacemark: [CLPlacemark]?, error: Error?) in
                          guard let place = clPlacemark?.first else {
                              print("No placemark from Apple: \(String(describing: error))")
                              return
                          }
              
                          if let addrList = place.addressDictionary?["FormattedAddressLines"] as? [String] {
                              let addressString = addrList.joined(separator: ", ")
                              print(addressString)
              
                          }
                      }
              

              【讨论】:

                猜你喜欢
                • 2023-03-10
                • 2011-04-20
                • 1970-01-01
                • 2012-06-16
                • 1970-01-01
                • 2011-08-11
                • 2012-10-01
                • 2013-05-06
                • 1970-01-01
                相关资源
                最近更新 更多