Как я могу получить доступ к значениям в необязательном NSSingleObjectArrayI?

#ios #json #swift

#iOS #json #swift

Вопрос:

Я не знаю, как получить доступ к значению ‘duration’ в моем вложенном необязательном NSSingleObjectArrayI, который создается из ответа JSON. Как мне получить доступ к вложенным значениям в этой структуре данных?

Когда я вызываю print(firstRow[«элементы»]), я получаю следующий вывод:

 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 Massachusetts Ave, Cambridge, MAamp;departure_time=nowamp;key=AIzaSyB65D4XHv6PkqvWJ7C-cFvT1QHi9OkqGCEamp;origins=428 Memorial Dr, Cambridge, MA
  

Комментарии:

1. Не могли бы вы добавить оригинальный json и проанализировать код, пожалуйста? Таким образом, помочь вам будет намного проще.

2. Также не могли бы вы сначала попытаться развернуть свой массив? Например, так: firstRow [‘элементы’] [0] [‘длительность’] или firstRow [‘элементы’].first [‘длительность’]

3. Используйте Codable, а не JSONSerialization.

4. @matt Не могли бы вы, пожалуйста, уточнить? Я не очень знаком с Codable.

5. @AntonVlasov Я попробовал это и получил ноль: (

Ответ №1:

Видя ваш вывод, ваш firstRow["elements"] необязателен, поэтому вам нужно развернуть его. И на самом деле это NSArray с одним элементом, где единственным элементом является словарь, с 4 записями — «расстояние», «длительность», «duration_in_traffic» и «статус». Возможно, вам потребуется преобразовать элемент в словарь, чтобы получить доступ к каждой записи.

Для этой цели вы можете использовать необязательную привязку с as? -приведением:

 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 s трудно читать, поэтому кому-то это понравится как:

 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, который является современным способом работы с JSON в Swift.

Комментарии:

1. Спасибо! Я очень легко внедрил Codeable и получил свои кодируемые классы через swiftjson.com

2. @Willy, кажется, ты нашел симпатичный сайт для работы Codable . Удачного кодирования.