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



我正在尝试制作一个具有两个主要焦点的 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 个符合可编码协议的结构。第一个将保存整个响应数据

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

}

保持漂亮

关于你的 Idk,但我不喜欢看丑陋的代码。为了保持干净,我们将把你制作的函数分成两部分。最好有一堆较小的可读/可重用函数,每个函数完成一个任务,而不是 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
}

最新更新