Ошибка SIGABRT в Swift при десериализации JSON - PullRequest
0 голосов
/ 14 января 2020

Я пытаюсь создать приложение Swift с двумя основными фокусами. Одним из них является отображение всех данных с URL-адреса в ScrollView, а другим - кнопка для получения случайного названия игры.

Кнопка работает, и я получаю случайную игру, но когда я пытаюсь загрузить приложение с помощью UIScrollView, я получаю SIGABRT в строке 33. Любая помощь приветствуется

РЕДАКТИРОВАТЬ: I с тех пор исправил SIGABRT, но я не могу отобразить какую-либо информацию в UIScrollView. Кто-нибудь видит какие-либо вопиющие проблемы в коде сейчас?

@IBOutlet weak var infoView: UIView!   
@IBOutlet weak var label: UILabel!
@IBOutlet weak var labelScroll: UILabel!

override func viewDidLoad() {
   super.viewDidLoad()
   parseGame()
}

func parseGame() {
    let url: URL = URL(string:     "https://www.giantbomb.com/api/games/?api_key=5094689370c2cf4ae42a2a268af0595badb1fea8&format=json&field_list=name")!
        print(url)
        let responseData: Data? = try? Data(contentsOf: url)
        if let responseData = responseData {
            let json: Any? = try? JSONSerialization.jsonObject(with: responseData, options: [])
            print(json ?? "Couldn't get JSON")
            if let json = json {
                let dictionary: [String: Any]? = json as? [String: Any]
                if let dictionary = dictionary {
                    guard let result = dictionary["results"] as? [String:Any]?  else { return }
                    if let result = result {
                        let name = result["name"] as? String?
                        if let name = name {
                            for i in 1...100 {
                                labelScroll.text = "Name: \(name)"
                        }
                    }
                }
            }
        }
    }
}

1 Ответ

2 голосов
/ 30 января 2020

О нет! Это json разбор пирамиды смерти!

Небольшая альтернатива

Если вы знаете структуру json, которую вы будете получать, вы можете создать некоторые структуры для моделирования ваших данных. Также у Swift есть классный протокол, называемый «Codable», который делает много усилий при разборе json и преобразовании его в объект, который вы создаете в коде.

Давайте смоделируем данные!

Мы создадим 2 структуры, которые соответствуют Codable Protocol. Первая будет содержать все данные ответа

struct ApiGameReponse:Codable {

    var error:String
    var limit:Int
    var offset:Int
    var pages:Int
    var totalResults:Int
    var status:Int
    var version:String
    var games:[Game]


    private enum CodingKeys:String, CodingKey {
        //The enum's rawValue needs to match the json's fieldName exactly.
        //That's why some of these have a different string assigned to them.
        case error
        case limit
        case offset
        case pages = "number_of_page_results"
        case totalResults = "number_of_total_results"
        case status = "status_code"
        case version
        case games = "results"
    }

}

, а вторая структура будет моделировать наш игровой объект. (Это единственная строка, да, я знаю, что это очень увлекательно ...) Поскольку эти конкретные данные json представляют игру только с одним свойством name, нам не нужна целая структура, но если json был другим и скажем, имеет свойства "gamePrice" и "жанр", структура будет лучше смотреть.

struct Game:Codable {

    var name:String

}

Сохраняйте это красиво

Спасибо вам, но я не люблю смотреть на уродливый код. Чтобы сохранить его в чистоте, мы разделим функцию you на две части. Всегда лучше иметь кучу меньших читаемых / многократно используемых функций, каждая из которых выполняет одну задачу, а не 1 superSizeMe номер 3 с большим коксом.

Получение данных

Часть 1: Получить данные из URL

func getJSONData(_ urlString: String) -> Data? {
        guard
        let url:URL = URL(string: urlString),
        let jsonData:Data = try? Data(contentsOf: url)
        else { return nil }
        return jsonData
}

Часть 2. Декодирование данных во что-то, что мы можем использовать

func getGameNames() -> [String] {
        let apiEndpoint = "https://www.giantbomb.com/api/games/?api_key=5094689370c2cf4ae42a2a268af0595badb1fea8&format=json&field_list=name"
        guard
        let data = getJSONData(apiEndpoint),
        let response = try? JSONDecoder().decode(ApiGameReponse.self, from: data)
        else { return [] }
        //Neat little function "map" allows us to create an array names from the array of game objects.
        let nameArray = response.games.map { $0.name }
        return nameArray
    }

Реализация

И, наконец, мы можем получить имена и использовать их по мере необходимости.

override func viewDidLoad() {
        //I recommend putting this somewhere else
        //Perhaps create a method called "setup()" and call it in this class's inializer.
        let names = getGameNames()
        print(names) //Implement the array of names as needed
    }
...