在swift 3.0中解析字典

时间:2017-01-18 06:37:55

标签: swift dictionary

我使用google places api来获取经度和纬度,但无法解析字典。我正在使用以下代码

 let lat = ((((dic["results"] as! AnyObject).value(forKey: "geometry") as AnyObject).value(forKey: "location") as AnyObject).value(forKey: "lat") as AnyObject).object(0) as! Double

错误:无法调用非功能类型的值'Any?!'

我还检查过nsdictionary而不是Anyobject但是没有用。 任何人都可以知道如何正确地从上面的代码中获取lat。

回应:

{
results =     (
            {
        "address_components" =             (
                            {
                "long_name" = Palermo;
                "short_name" = Palermo;
                types =                     (
                    locality,
                    political
                );
            },
                            {
                "long_name" = "Province of Palermo";
                "short_name" = PA;
                types =                     (
                    "administrative_area_level_2",
                    political
                );
            },
                            {
                "long_name" = Sicily;
                "short_name" = Sicily;
                types =                     (
                    "administrative_area_level_1",
                    political
                );
            },
                            {
                "long_name" = Italy;
                "short_name" = IT;
                types =                     (
                    country,
                    political
                );
            }
        );
        "formatted_address" = "Palermo, Italy";
        geometry =             {
            bounds =                 {
                northeast =                     {
                    lat = "38.219548";
                    lng = "13.4471566";
                };
                southwest =                     {
                    lat = "38.0615392";
                    lng = "13.2674205";
                };
            };
            location =                 {
                lat = "38.1156879";
                lng = "13.3612671";
            };
            "location_type" = APPROXIMATE;
            viewport =                 {
                northeast =                     {
                    lat = "38.2194316";
                    lng = "13.4471566";
                };
                southwest =                     {
                    lat = "38.0615392";
                    lng = "13.2674205";
                };
            };
        };
        "place_id" = ChIJmdBOgcnoGRMRgNg7IywECwo;
        types =             (
            locality,
            political
        );
    }
);
status = OK;

}

3 个答案:

答案 0 :(得分:7)

您必须分多步解析JSON,为清楚起见,我建议使用类型别名:

typealias JSONDictionary = [String:Any]
    let results = dic["results"] as? [JSONDictionary] {
      for result in results {
        if let geometry = result["geometry"] as? JSONDictionary,
           let location = geometry["location"] as? JSONDictionary {
              if let lat = location["lat"] as? Double,
                 let lng = location["lng"] as? Double {
                   print(lat, lng)
              }
        }
     }
   }

Swift中的一些规则:

  • 除非您完全没有选择,否则请勿使用NSDictionary / NSArray
  • Swift 3中的JSON字典是[String:Any],是JSON数组[[String:Any]]
  • 尽可能详细地展示Any类型。
  • 从远程服务器解析JSON时,始终使用可选绑定以避免运行时错误。

答案 1 :(得分:4)

Kristijan的答案有些正确,但它忽略了许多重要的语法和可选的类型转换。假设您的代码中某处正在进行实际的API调用:

class SomeClass {
    func getLocationData() {
        //do your api call stuff here and get "result"
        let location: Location? = Location(json: result as? [String:Any])
    }
}

您可以通过某种方式处理响应,可能使用结构:

struct Location {
    var lat: Double
    var long: Double

    init(lat: Double, long: Double) {
        self.lat = lat
        self.long = long
    }

    init?(json: [String:Any]?) {
        guard let results = json?["results"] as? [Any],
            let first = results[0] as? [String:Any],
            let geometry = first["geometry"] as? [String:Any],
            let location = geometry["location"] as? [String:Any],
            let latitude = location["lat"] as? Double,
            let longitude = location["lng"] as? Double else {
            return nil
        }
        self.lat = latitude
        self.long = longitude
    }
}

struct initializer中的一点是使用条件展开来将JSON响应对象的各个成员类型转换为适当的类型。

请注意,根据您从API接收的实际JSON对象,这可能会有很大差异。除了您已经尝试编写以解析它的Swift代码之外,如果您可以在原始文本中发布实际的JSON响应将会很有帮助。我的回复会根据您提供的信息做到最好。如果您从API响应中提供原始JSON对象,我可能会写一些更有信心的东西。

编辑:以下是Playground代码段,用于检索和解析Google Places API中的结果

import PlaygroundSupport
import Foundation

PlaygroundPage.current.needsIndefiniteExecution = true

struct Location {
    var lat: Double
    var long: Double

    init(lat: Double, long: Double) {
        self.lat = lat
        self.long = long
    }

    init?(json: [String:Any]?) {
        guard let results = json?["results"] as? [Any],
            let first = results[0] as? [String:Any],
            let geometry = first["geometry"] as? [String:Any],
            let location = geometry["location"] as? [String:Any],
            let latitude = location["lat"] as? Double,
            let longitude = location["lng"] as? Double else {
            return nil
        }
        self.lat = latitude
        self.long = longitude
    }
}

func getLocationData() {
    let base = "https://maps.googleapis.com/maps/api/geocode/json"
    let args = [
        "address=%50%61%6C%65%72%6D%6F%2C%20%50%72%6F%76%69%6E%63%65%20%6F%66%20%50%61%6C%65%72%6D%6F%2C%20%49%74%61%6C%79",
        "sensor=false",
    ]

    let urlStr = "\(base)?\(args.joined(separator: "&"))"
    guard let url = URL(string: urlStr) else { return }
    var request = URLRequest(url: url)
    request.httpMethod = "GET"

    URLSession.shared.dataTask(with: request,
        completionHandler: { (data, response, error) -> Void in
            guard let jsonData = data else { return }
            if let jsonResult = try? JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) as? [String:Any] {
                let location: Location? = Location(json: jsonResult)
                print("Location: \(location?.lat), \(location?.long)")
            }
        }
    ).resume()
}

getLocationData()

答案 2 :(得分:0)

let geometry = = item["geometry"] as NSArray
let location = geometry["location"] as Dictionary

let latitude = location["lat"] as Double
let longitude = location["long"] as Double

试试这个,它从头开始,所以我不记得它100%正确,但你有几何数组内的位置字典和内部位置有lat / long参数。