如何访问可选NSSingleObjectArrayI中的值?

时间:2019-04-04 18:16:45

标签: ios json swift

我不知道如何在由JSON响应构造的嵌套的可选NSSingleObjectArrayI中访问'duration'值。如何访问此数据结构中的嵌套值?

当我调用print(firstRow [“ elements”])时,得到以下输出:

Optional(<__NSSingleObjectArrayI 0x60000120f920>(
{
    distance = {
        text = "1.8 km";
        value = 1754;
    };
    duration = {
        text = "5 mins";
        value = 271;
    };
    "duration_in_traffic" = {
        text = "4 mins";
        value = 254;
    };
    status = OK;
}
))

我尝试了字符串索引(firstRow ['elements'] ['duration']),但出现错误。

fetchData { (dict, error) in
    if let rows = dict?["rows"] as? [[String:Any]]{
        if let firstRow = rows[0] as? [String:Any]{
            print("firstRow is")
            print(firstRow["elements"])
            // Trying to access duration within firstRow['elements'] here           
        }
    }
}

作为参考,这是fetchData函数:

func fetchData(completion: @escaping ([String:Any]?, Error?) -> Void) {

    let url = getRequestURL(origin: "test", destination: "test")!;

    let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
        guard let data = data else { return }
        do {
            if let array = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String:Any]{
                completion(array, nil)
            }
        } catch {
            print(error)
            completion(nil, error)
        }
    }
    task.resume()
}

一个示例HTTP JSON请求在这里:

https://maps.googleapis.com/maps/api/distancematrix/json?destinations=77%20Massachusetts%20Ave,%20Cambridge,%20MA&departure_time=now&key=AIzaSyB65D4XHv6PkqvWJ7C-cFvT1QHi9OkqGCE&origins=428%20Memorial%20Dr,%20Cambridge,%20MA

1 个答案:

答案 0 :(得分:0)

看到您的输出,您的firstRow["elements"]是可选的,因此您需要对其进行包装。它实际上是一个具有单个元素的NSArray,其中唯一的元素是Dictionary,具有4个条目-“距离”,“持续时间”,“ duration_in_traffic”和“状态”。您可能需要将元素强制转换为Dictionary才能访问每个条目。

您可以为此目的在as?-casting中使用可选绑定:

fetchData { (dict, error) in
    if let rows = dict?["rows"] as? [[String: Any]] {
        if let firstRow = rows.first {
            print("firstRow is")
            print(firstRow["elements"])
            //Unwrap and cast `firstRow["elements"]`.
            if let elements = firstRow["elements"] as? [[String: Any]] {
                //The value for "duration" is a Dictionary, you need to cast it again.
                if let duration = elements.first?["duration"] as? [String: Any] {
                    print(duration["text"] as? String)
                    print(duration["value"] as? Int)
                }
            }
        }
    }
}

嵌套太深的if很难阅读,所以有人会这样想:

fetchData { (dict, error) in
    if
        let rows = dict?["rows"] as? [[String: Any]],
        let firstRow = rows.first,
        let elements = firstRow["elements"] as? [[String: Any]],
        let duration = elements.first?["duration"] as? [String: Any]
    {
        print(duration["text"] as? String)
        print(duration["value"] as? Int)
    }
}

或者使用guard可能是更好的解决方案。


否则,如果您可以以可读的格式向我们展示整个JSON文本,那么有人会向您展示如何使用Codable,这是在Swift中使用JSON的现代方式。