JSON 反序列化时 Swift 中的 SIGABRT 错误

SIGABRT error in Swift when JSON deserializing

我正在尝试制作一个有两个主要重点的 Swift 应用程序。一种是在 ScrollView 中显示来自 URL 的所有数据,另一种是用于获取游戏随机名称的按钮。

按钮有效,我得到一个随机游戏,但是当我尝试使用 UIScrollView 加载应用程序时,我在第 33 行收到 SIGABRT。 感谢任何帮助

编辑:我已经修复了 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)"
                        }
                    }
                }
            }
        }
    }
}

哦不!这是json解析死亡金字塔!

一个不错的小选择

如果您知道 json 您将收到的结构,您可以创建一些结构来为您的数据建模。 Swift 还有一个很酷的协议,称为“Codable”,它在解析 json 并将其转换为您在代码中创建的对象方面做了很多繁重的工作。

让我们对数据建模!

我们将创建 2 个符合 Codable 协议的结构。第一个将保存整个响应数据

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 数据代表一个只有 1 个名称的游戏 属性 我们真的不需要一个完整的结构,但是如果json 不同,据说有“gamePrice”和“genre”属性,一个结构会更好看。

struct Game:Codable {
 
    var name:String
    
}

保持漂亮

很了解你,但我不喜欢看丑陋的代码。为了保持干净,我们将把函数 you 分成两部分。最好有一堆较小的 readable/reusable 函数,每个函数都完成一个任务,而不是 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 { [=13=].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
    }