Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
iOS 9中的CLPlacemark到字符串_Ios_Objective C_Swift_Geocoding - Fatal编程技术网

iOS 9中的CLPlacemark到字符串

iOS 9中的CLPlacemark到字符串,ios,objective-c,swift,geocoding,Ios,Objective C,Swift,Geocoding,我想将CLPlacemark格式化为字符串 众所周知的方法是使用ABCreateStringWithAddressDictionary,但它在iOS 9中被弃用。警告告诉我改用CNPostalAddressFormatter 但是,CNPostalAddressFormatter只能格式化CNPostalAddress。无法将CLPlacemark正确转换为CNPostalAddress;只有这三个属性由CLPlacemark和CNPostalAddress共享:国家/地区、等国家/地区代码和邮

我想将
CLPlacemark
格式化为字符串

众所周知的方法是使用
ABCreateStringWithAddressDictionary
,但它在iOS 9中被弃用。警告告诉我改用
CNPostalAddressFormatter

但是,
CNPostalAddressFormatter
只能格式化
CNPostalAddress
。无法将
CLPlacemark
正确转换为
CNPostalAddress
;只有这三个属性由
CLPlacemark
CNPostalAddress
共享:
国家/地区
等国家/地区代码
邮政编码


那么,我现在应该如何将
CLPlacemark
格式化为字符串呢?

获取placemark的
addressDictionary
,并使用其
“FormattedAddressLines”
键提取地址字符串。请注意,这是字符串行的数组

(不过,你是对的,负责转换到Contacts框架的苹果开发者似乎完全忘记了通讯录和CLPlacemark之间的交换。这是Contacts框架中的一个严重缺陷,是众多缺陷之一。)


编辑因为我最初发布了这个答案,苹果修复了这个错误。CLPlacemark现在有一个
postalAddress
属性,它是一个CNPostalAddress,然后您可以使用CNPostalAddressFormatter来获得一个漂亮的多行地址字符串。确保导入联系人

Swift 4.1(和3&4,保存1行) 我阅读该问题是为了问“我该如何实施?” 两种方法 和其他海报一样,我首先选择移植AddressDictionary方法。但这意味着将失去
CNPostalAddress
类和格式化程序的功能和灵活性。因此,方法2

extension String {
    // original method (edited)
    init?(depreciated placemark1: CLPlacemark?) {
    // UPDATE: **addressDictionary depreciated in iOS 11**
        guard
            let myAddressDictionary = placemark1?.addressDictionary,
            let myAddressLines = myAddressDictionary["FormattedAddressLines"] as? [String]
    else { return nil }

        self.init(myAddressLines.joined(separator: " "))
}

    // my preferred method - let CNPostalAddressFormatter do the heavy lifting
    init?(betterMethod placemark2: CLPlacemark?) {
        // where the magic is:
        guard let postalAddress = CNMutablePostalAddress(placemark: placemark2) else { return nil }
        self.init(CNPostalAddressFormatter().string(from: postalAddress))
    }
}
等等,那是什么→ <代码>CNPostalAddress初始值设定项

extension CNMutablePostalAddress {
    convenience init(placemark: CLPlacemark) {
        self.init()
        street = [placemark.subThoroughfare, placemark.thoroughfare]
            .compactMap { $0 }           // remove nils, so that...
            .joined(separator: " ")      // ...only if both != nil, add a space.
    /*
    // Equivalent street assignment, w/o flatMap + joined:
        if let subThoroughfare = placemark.subThoroughfare,
            let thoroughfare = placemark.thoroughfare {
            street = "\(subThoroughfare) \(thoroughfare)"
        } else {
            street = (placemark.subThoroughfare ?? "") + (placemark.thoroughfare ?? "")
        } 
    */
        city = placemark.locality ?? ""
        state = placemark.administrativeArea ?? ""
        postalCode = placemark.postalCode ?? ""
        country = placemark.country ?? ""
        isoCountryCode = placemark.isoCountryCode ?? ""
        if #available(iOS 10.3, *) {
            subLocality = placemark.subLocality ?? ""
            subAdministrativeArea = placemark.subAdministrativeArea ?? ""
        }
    }
}
用法 在这里之前读书的人都会得到一件免费的T恤。(不太可能)

*该代码适用于Swift 3和4,但用于删除零值的
flatMap
已在Swift 4.1(文件,或参见以获取基本原理)中被折旧/重命名为
compactMap

Swift 3.0
Swift 3.0辅助方法

class func addressFromPlacemark(_ 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
      }

FormattedAddressLines按以下顺序返回数组:名称、街道、城市、州、邮政编码、国家。如果你打印placeString,你会看到类似这样的内容:“苹果公司,1无限循环,美国加利福尼亚州库珀蒂诺95014号”。你可以将你的代码显著提高1。在示例代码2中不使用其他库。使用
flatMap
+
joined
3。空合并,因为
CNPostalAddress
的所有成员都非空。附言:那么你就不必承诺免费t恤:P@Andy1]谢谢,隐藏分机已删除。2]
flatMap
+
已加入
。嗯,我会在评论中添加一个替代方案,告诉我你是否更喜欢它。3] 这是因为不能为它们分配
CLPlacemark
的字符串选项--CLPlacemark的属性需要合并,而不是
CNPostalAddress
,在iOS 11中,
CLPlacemark
有一个
CNPostalAddress
getter。读者注意:在给出正确答案的2年多时间里,
addressDictionary
已经贬值(在iOS 11中)。科技的巨轮在……上滚滚而来,
CLPlacemark
get
var postalAddress:CNPostalAddress?{get}
属性,锁定整个线程@AmitaiB是的,它现在纯粹是历史上的兴趣。。。!
func quickAndDirtyDemo() {
    let location = CLLocation(latitude: 38.8977, longitude: -77.0365)

    CLGeocoder().reverseGeocodeLocation(location) { (placemarks, _) in
        if let address = String(depreciated: placemarks?.first) {
            print("\nAddress Dictionary method:\n\(address)") }

        if let address = String(betterMethod: placemarks?.first) {
            print("\nEnumerated init method:\n\(address)") }
    }
}

/* Output:
Address Dictionary method:
The White House 1600 Pennsylvania Ave NW Washington, DC  20500 United States

Enumerated init method:
1600 Pennsylvania Ave NW
Washington DC 20500
United States
*/
if let lines = myCLPlacemark.addressDictionary?["FormattedAddressLines"] as? [String] {
    let placeString = lines.joined(separator: ", ")
    // Do your thing
}
class func addressFromPlacemark(_ 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
      }