Анализ JSON Data Swift «Поток 4: Неустранимая ошибка: неожиданно обнаружен ноль при развертывании необязательного значения» - PullRequest
0 голосов
/ 29 мая 2020

Я пытаюсь проанализировать некоторые JSON данные, возвращенные при вызове API. Путь, по которому я хочу двигаться, - это медиа> лица> точки. Я могу перемещаться по лицам, но проблема заключается в получении очков.

вот код


let dictionary = try JSONSerialization.jsonObject(with: data!, options:.mutableContainers) as? [String:Any]

let media = dictionary!["media"] as? [String: Any]
print(media!["faces"]) // Works see the returned data below
let faces = media!["faces"] as? [String: Any]
print(faces!["points"]) // Thread 4: Fatal error: Unexpectedly found nil while unwrapping an Optional value

API вернул данные для печати (media! ["Faces"])

{
    angle = "1.2222";
    "appearance_id" = 0;
    "detection_score" = 1;
    duration = "00:00:00";
    "face_uuid" = "78338d20-9ced-11ea-b153-0cc47a6c4dbd";
    height = "74.31999999999999";
    "media_uuid" = "fec83ac3-de00-44f0-ad5b-e1e990a29a8c";
    "person_id" = "";
    points =     (
                {
            name = "basic eye left";
            type = 512;
            x = "85.16";
            y = "86.62";
        },
                {
            name = "basic eye right";
            type = 768;
            x = "110.92";
            y = "86.66";
        }

Ответы [ 2 ]

0 голосов
/ 29 мая 2020

Основная проблема здесь заключается в том, что вы принудительно разворачиваете опции, которые, как вы не можете гарантировать, имеют значение - и когда они не имеют значения, вызывающего фатальную ошибку.

Лучшим подходом является развертывание переменные безопасно и выдают ошибку, если вам нужно ее обработать. Я попытался показать несколько различных способов сделать это ниже.

guard let data = data else { return }
do {
    let dictionary = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String:Any]
    guard let media = dictionary?["media"] as? [String: Any] else { throw MyError.mediaNotFoundError }

    if let faces = media["faces"] as? [String: Any] {
        print(faces)

        guard let points = faces["points"] else { throw MyError.pointsNotFound}
        print(points)
    } else {
        throw MyError.facesNotFound
    }
} catch {
    // Handle error here
}

Обратите внимание, я использовал настраиваемое перечисление ошибок. Я бы также посоветовал добавить к нему локализованное описание, чтобы добавить больше деталей для отладки.

enum MyError: Error {
    case mediaNotFoundError
    case facesNotFound
    case pointsNotFound
}

Я бы также рекомендовал прочитать этот ответ здесь для более подробного объяснения опции.

0 голосов
/ 29 мая 2020

Так как ты новичок, я тебе помогаю. Эти вопросы задавали много раз (высока вероятность того, что вы получите повторяющийся флаг). Вот как можно избежать подобных ошибок: старайтесь не использовать принудительное развертывание (этот символ !) где-либо без исключения, чтобы избежать этих ошибок. Вместо if let вы можете использовать guard let, это ваш личный выбор.

if let data = data,
    let dictionary = try JSONSerialization.jsonObject(with: data, options:.mutableContainers) as? [String: Any],
    let media = dictionary["media"] as? [String: Any],
    let faces = media["faces"] as? [[String: Any]],
    let points = faces[0]["points"] {
    print(points)
}

Изменить: поскольку параметр "faces" представляет собой массив, вам необходимо проанализировать их как Array, а не как Dictionary. В приведенном выше примере показано, как перейти к первому набору "points".

Обновление: Лучше использовать JSONDecoder. Вот как: Создайте эту структуру вне класса:

struct Response: Codable { var media: Media }
struct Media: Codable { var faces: [Face] }
struct Face: Codable { var points: [Point] }
struct Point: Codable { }

А затем декодируйте следующим образом:

if let data = data,
    let response = try JSONDecoder().decode(Response.self, from: data) {
    print(response.media.faces[0].points)
}
...